diff --git a/.github/workflows/Build-Release.yml b/.github/workflows/Build-Release.yml index 233a1bac58..ce662d09df 100644 --- a/.github/workflows/Build-Release.yml +++ b/.github/workflows/Build-Release.yml @@ -34,6 +34,26 @@ jobs: - name: Restore dependencies run: dotnet restore ./src/EPPlus.sln + + # --- SBOM --- + - name: Install CycloneDX + run: dotnet tool install --global CycloneDX + - name: Read version from csproj + id: read_version + run: | + $version = ([xml](Get-Content ./src/EPPlus/EPPlus.csproj)).Project.PropertyGroup.Version | Where-Object { $_ } | Select-Object -First 1 + echo "VERSION=$version" >> $env:GITHUB_ENV + shell: pwsh + - name: Generate SBOM + run: dotnet CycloneDX ./src/EPPlus/EPPlus.csproj -o ./sbom -F Json -st Library -sv ${{ env.VERSION }} -fn epplus-${{ env.VERSION }}.sbom.json -imp ./src/EPPlus/sbom-metadata-template.xml + - name: Generate SHA-256 checksum for SBOM + run: | + $sbomFile = "./sbom/epplus-${{ env.VERSION }}.sbom.json" + $hash = (Get-FileHash -Path $sbomFile -Algorithm SHA256).Hash.ToLower() + "$hash epplus-${{ env.VERSION }}.sbom.json" | Out-File -FilePath "./sbom/epplus-${{ env.VERSION }}.sbom.json.sha256" -Encoding utf8NoBOM + shell: pwsh + # --- SBOM --- + - name: Build run: dotnet build ./src/EPPlus.sln --no-restore --configuration Release - name: Test diff --git a/docs/articles/breakingchanges.md b/docs/articles/breakingchanges.md index d6abb22c67..330ff3421f 100644 --- a/docs/articles/breakingchanges.md +++ b/docs/articles/breakingchanges.md @@ -216,8 +216,19 @@ Renaming worksheet's will now change the formula correctly to include single quo ### 8.0.2 * Removed base class from ExcelVmlDrawingPosition and with that the Load, UpdateXml methods and the RowOff and ColOff properties as they were duplicates. +### 8.5.0 +* Setting dataLabelPosition.Top on BarCharts corrupted the excel file when saved. Trying to set this now throws an error instead. +* NumberFormatToTextArgs.NumberFormat now returns the interface IExcelNumberFormat rather than the ExcelNumberFormatXml class. All public variables remain the same and it can be safely cast to ´ExcelNumberFormatXml´ as long as ´Package.Workbook.NumberFormatToTextHandler´ is null. + ### 8.5.5 * `ws.Cells["A1"].RichText` no longer sets cells with `null` to `string.empty` * .RichText no longer sets the cell or contents to be RichText automatically. - This is instead done when properties such as; `.Text`, `.Add` or `.Insert` are set on the .RichText property. \ No newline at end of file + This is instead done when properties such as; `.Text`, `.Add` or `.Insert` are set on the .RichText property. +The misspelled enum eCompundLineStyle has been renamed eCompoundLineStyle. + + +### 9.0.0 +The misspelled enum eCompundLineStyle has been renamed eCompoundLineStyle. +The misspelled property on drawingFill `Transparancy` has been renamed to `Transparency` +The `Richtext.Baseline` property now always return that value in whole percent. \ No newline at end of file diff --git a/docs/articles/fixedissues.md b/docs/articles/fixedissues.md index 72b47d5c0b..f763512770 100644 --- a/docs/articles/fixedissues.md +++ b/docs/articles/fixedissues.md @@ -1,4 +1,6 @@ # Features / Fixed issues - EPPlus 8 +## Version 9.0.0 +* Added 'Layout' property to 'ExcelChartTrendlineLabel' class. ## Version 8.6 1 ### Features diff --git a/src/.runsettings b/src/.runsettings index 74acb790f1..2c84e809bf 100644 --- a/src/.runsettings +++ b/src/.runsettings @@ -16,5 +16,6 @@ False False False + true \ No newline at end of file diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 564eca7234..bacdaf92bd 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -3,9 +3,10 @@ true + - + @@ -17,9 +18,9 @@ - - - + + + \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/BarChartTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/BarChartTests.cs new file mode 100644 index 0000000000..c786c38b92 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/BarChartTests.cs @@ -0,0 +1,83 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class BarChartTests : TestBase + { + [TestMethod] + public void GenerateSvgForBarCharts1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("BarChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(x => { x.Size.Width = 100; x.Size.Height = 100; }); + SaveTextFileToWorkbook($"svg\\BarChartForSvg_sheet1_{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForBarCharts2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("BarChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\BarChartForSvg_sheet2_{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void DatalabelBarCharts() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("BarChartForSvgDatalabelsBasic.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var drawings = ws.Drawings; + var ix = 1; + + for (int i = ix; i < drawings.Count; i++) + { + var svg = drawings[i].ToSvg(); + SaveTextFileToWorkbook($"svg\\BarChartDataLabels{ix++}.svg", svg); + } + } + } + + + [TestMethod] + public void NegativeDatalabelBarCharts() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("negativeDatalabels.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var drawings = ws.Drawings; + var ix = 0; + + for (int i = ix; i < drawings.Count; i++) + { + var svg = drawings[i].ToSvg(); + SaveTextFileToWorkbook($"svg\\NegativeLabels{ix++}.svg", svg); + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/ColumnChartTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/ColumnChartTests.cs new file mode 100644 index 0000000000..6d6002687e --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/ColumnChartTests.cs @@ -0,0 +1,57 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class ColumnChartTests : TestBase + { + [TestMethod] + public void GenerateSvgForColumnCharts1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ColumnChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ColumnChartForSvg_sheet1_{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForColumnCharts2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ColumnChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + + //var ix = 2; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ColumnChartForSvg_sheet2_{ix++}.svg", svg); + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/ComboChartTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/ComboChartTests.cs new file mode 100644 index 0000000000..37b69fe8f7 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/ComboChartTests.cs @@ -0,0 +1,31 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class ComboChartToSvgTests : TestBase + { + [TestMethod] + public void GenerateSvgForComboCharts_sheet1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ComboChart.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\ComboChart_Sheet1_{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ComboChart_sheet1_{ix++}.svg", svg); + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/ErrorbarsTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/ErrorbarsTests.cs new file mode 100644 index 0000000000..3b2ea9db41 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/ErrorbarsTests.cs @@ -0,0 +1,70 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class ErrorbarsTests : TestBase + { + [TestMethod] + public void GenerateSvgForErrorbars_Line_Sheet1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("Errorbars.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Error_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Errorbar_sheet1_{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForErrorbars_Column_Sheet2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("Errorbars.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Error_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Errorbar_sheet2_{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForErrorbars_Bar_Sheet3() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("Errorbars.xlsx")) + { + var ws = p.Workbook.Worksheets[2]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Error_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Errorbar_sheet3_{ix++}.svg", svg); + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/LineChartToSvgTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/LineChartToSvgTests.cs new file mode 100644 index 0000000000..5ea7ab57f6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/LineChartToSvgTests.cs @@ -0,0 +1,307 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class LineChartToSvgTests : TestBase + { + [TestMethod] + public void GenerateSvgForLineCharts_sheet1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + var ix = 6; + var c = ws.Drawings[ix]; + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg); + + //for (int i = 0; i < ws.Drawings.Count; i++) + //{ + // var c = ws.Drawings[i]; + // var svg = c.ToSvg(); + // SaveTextFileToWorkbook($"svg\\ChartForSvg{i}.svg", svg); + //} + } + } + + [TestMethod] + public void GenerateSvgForLineCharts_sheet2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet2_{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet2_{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForLineCharts_sheet3() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[2]; + //var ix = 0; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\chartforsvg_sheet3_{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_Sheet3{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForComboCharts_sheet4() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[3]; + var ix = 1; + var c = ws.Drawings[ix]; + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet2_{ix++}.svg", svg); + //var ix = 1; + //foreach (ExcelChart c in ws.Drawings) + //{ + // var svg = c.ToSvg(); + // SaveTextFileToWorkbook($"svg\\ChartForSvg_Combo_Sheet4{ix++}.svg", svg); + //} + } + } + [TestMethod] + public void GenerateSvgForTrendlineCharts_sheet5() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws = p.Workbook.Worksheets[4]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\Trendline_sheet5_{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Trendline_Sheet5{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForLineCharts() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("LineChartRenderTest.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\LineChartForSvg_Single{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\LineChartForSvg{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void GenerateSuperScript() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg_SecondaryAxis.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet2_{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_SecAxis{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForCharts_SecondaryAxis_sheet2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg_SecondaryAxis.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + //var ix = 2; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_Sheet2_SecAxis{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_Sheet2_SecAxis{ix++}.svg", svg); + } + } + } + [TestMethod] + public void GenerateSvgForCharts_SecondaryAxis_sheet3() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("ChartForSvg_SecondaryAxis.xlsx")) + { + var ws = p.Workbook.Worksheets[2]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet3_{ix++}.svg", svg); + var ix = 1; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChartForSvg_Sheet3_SecAxis{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void GenerateSimplestChart() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("SimplestChart.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\SimplestChartTitle.svg", svg); + } + } + + + [TestMethod] + public void GenerateDataLabels() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("datalabelsSvg.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\datalabelsAttempt.svg", svg); + } + } + + + + [TestMethod] + public void GenerateDataLabelsTrueMost() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("datalabelsSvgTrueMostWithFill.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\datalabelsSvgTrueMostWithFill.svg", svg); + } + } + + [TestMethod] + public void GenerateDataLabelsTrueMostAndManualLayout() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("datalabelsSvgTrueMostWithFillANDManual.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\datalabelsSvgTrueMostWithFillAndManual.svg", svg); + } + } + + [TestMethod] + public void GenerateDatalabelsLeaderLines() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("datalabelsSvgLeaderLinesAdjustedToBeSimilar.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\datalabelsSvgLeaderLines.svg", svg); + } + } + + + [TestMethod] + public void GenerateDatalabelsRightAlignedWithBg() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("datalabelsSvgRightAlignedWithBg.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\datalabelsSvgLeaderLinesBg.svg", svg); + } + } + + [TestMethod] + public void GenerateSimpleLineChart() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("defChartLine3Points.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\defChartLine3Points.svg", svg); + } + } + [TestMethod] + public void GenerateSvgForLineCharts_AxisAlign_sheet1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("HorizontalAxisAlign.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + //var ix = 3; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\HorizontalAxisChartForSvg{ix++}.svg", svg); + + for (int i = 0; i < ws.Drawings.Count; i++) + { + var c = ws.Drawings[i]; + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\HorizontalAxisChartForSvg{i}.svg", svg); + } + } + } + + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/PieChartTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/PieChartTests.cs new file mode 100644 index 0000000000..693294b5c4 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/PieChartTests.cs @@ -0,0 +1,34 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class PieChartTests : TestBase + { + + [TestMethod] + public void ReadAndCreateSvgsAll() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("PieChartSvgALL.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + for (int i = 0; i < p.Workbook.Worksheets.Count; i++) + { + ws = p.Workbook.Worksheets[i]; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\PieChartSvgALL\\s{i}_{ws.Name}_{c.Name}.svg", svg); + } + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Chart/TrendlineTests.cs b/src/EPPlus.DrawingRenderer.Tests/Chart/TrendlineTests.cs new file mode 100644 index 0000000000..219689525b --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Chart/TrendlineTests.cs @@ -0,0 +1,73 @@ +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; + +namespace EPPlus.Export.ImageRenderer.Tests.Chart +{ + [TestClass] + public class TrendlineTests : TestBase + { + [TestMethod] + public void GenerateSvgForTrendlines_Sheet1() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("Trendlines.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Trendline_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Trendline_sheet1_{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void TrendlineAlt() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("TrendlineAlt.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 4; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Trendline_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\TrendlineAlt_sheet1_{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void GenerateSvgForTrendlines_Sheet2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("Trendlines.xlsx")) + { + var ws = p.Workbook.Worksheets[1]; + + //var ix = 3; + //var c = ws.Drawings[ix]; + //var svg = c.ToSvg(); + //SaveTextFileToWorkbook($"svg\\Trendline_sheet1_ind{ix++}.svg", svg); + + var ix = 0; + foreach (ExcelChart c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\Trendline_sheet2_{ix++}.svg", svg); + } + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs new file mode 100644 index 0000000000..e2ce78fce8 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs @@ -0,0 +1,389 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.SvgItem; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; +using System.Drawing; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Tests.DrawingShapeRenderer +{ + [TestClass] + public class SvgStandAloneTests : TestBase + { + + private GroupRenderItem GenerateShapeRenderer() + { + BoundingBox bounds = new BoundingBox(0, 0, 500, 500); + StringBuilder sb = new StringBuilder(); + var svgShapeRenderer = new SvgShapeRenderer(bounds, sb, new SvgRenderOptions()); + + + var baseGroup = new GroupRenderItem(bounds); + + var background = new RectRenderItem(baseGroup.Bounds); + + background.Width = bounds.Width; + background.Height = bounds.Height; + background.FillColor = "aliceBlue"; + + baseGroup.AddChildItem(background); + return baseGroup; + } + + private GroupRenderItem GenerateGroupRenderItem() + { + BoundingBox bounds = new BoundingBox(0, 0, 500, 500); + + var baseGroup = new GroupRenderItem(bounds); + + var background = new RectRenderItem(baseGroup.Bounds); + + background.Width = bounds.Width; + background.Height = bounds.Height; + background.FillColor = "aliceBlue"; + + baseGroup.AddChildItem(background); + return baseGroup; + } + + private void GenerateSvgFile(string fileName, BoundingBox bounds, params RenderItem[] items) + { + + StringBuilder sb = new StringBuilder(); + var svgShapeRenderer = new SvgShapeRenderer(bounds, sb, new SvgRenderOptions()); + + List renderItems = items.ToList(); + svgShapeRenderer.Render(renderItems); + + var svg = sb.ToString(); + + SaveTextFileToWorkbook($"svg\\{fileName}.svg", svg); + } + + [TestMethod] + public void SvgRectTest() + { + var baseGroup = GenerateShapeRenderer(); + GenerateSvgFile("rectStandAlone", baseGroup.Bounds, baseGroup); + } + + [TestMethod] + public void SvgTextRun() + { + var baseGroup = GenerateShapeRenderer(); + + var rt = new RichTextFormatSimple(); + rt.Text = "My text"; + rt.UnderlineType = 1; + rt.FontColor = System.Drawing.Color.Black; + rt.Family = "Archivo Narrow"; + rt.SubFamily = OfficeOpenXml.Interfaces.Fonts.FontSubFamily.Regular; + rt.Size = 12f; + + var textRun = new SvgTextRunRenderItem(baseGroup.Bounds, rt, rt.Text, true); + + //Add size of text since svg renders text upwards from the start point. + textRun.YPosition = rt.Size; + + baseGroup.AddChildItem(textRun); + + GenerateSvgFile("textRunStandAlone", baseGroup.Bounds, baseGroup); + } + + private void GenerateTextBodyFile(string fileName, GroupRenderItem baseGroup, SvgTextBodyRenderItem textBody) + { + StringBuilder sb = new StringBuilder(); + var svgShapeRenderer = new SvgShapeRenderer(baseGroup.Bounds, sb, new SvgRenderOptions()); + + var background = new RectRenderItem(baseGroup.Bounds); + + background.Width = baseGroup.Bounds.Width; + background.Height = baseGroup.Bounds.Height; + background.FillColor = "aliceBlue"; + + baseGroup.AddChildItem(textBody); + baseGroup.AddChildItem(background); + + List items = new List() { baseGroup }; + + svgShapeRenderer.Render(items); + + var svg = sb.ToString(); + + + SaveTextFileToWorkbook($"svg\\{fileName}.svg", svg); + } + + + private SvgTextBodyRenderItem GenerateTextBody(GroupRenderItem baseGroup) + { + var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + var renderContext = new RenderContext(() => engine); + var textBody = new SvgTextBodyRenderItem(renderContext, baseGroup.Bounds, true); + var paragraph = textBody.AddParagraph("Hello"); + + paragraph.AddText(" There"); + + var rtItem = new RichTextFormatSimple("Second paragraph", "Archivo Narrow", 16f, true); + rtItem.FontColor = Color.DarkGreen; + var para2 = textBody.AddParagraph(rtItem); + + textBody.AddChildItem(paragraph); + textBody.AddChildItem(para2); + + baseGroup.AddChildItem(textBody); + + return textBody; + } + + [TestMethod] + public void SvgTextBodyTest() + { + var baseGroup = GenerateGroupRenderItem(); + var textBody = GenerateTextBody(baseGroup); + GenerateSvgFile("standAloneTextBody", baseGroup.Bounds, baseGroup); + } + + [TestMethod] + public void SvgTextBodyTestCenterAlignmentGenerated() + { + var baseGroup = GenerateGroupRenderItem(); + + var textBody = GenerateTextBody(baseGroup); + textBody.Paragraphs[0].AddText(" a\r\n new day beckons"); + textBody.Paragraphs[0].HorizontalAlignment = RenderItems.Shared.TextAlignment.Center; + + textBody.Paragraphs[1].HorizontalAlignment = RenderItems.Shared.TextAlignment.Center; + textBody.Paragraphs[1].AddText("\r\n What fun, what fun!"); + + //Text was added to the paragraph above the last paragraph + //We must re-calculate where the next paragraph should be placed + textBody.RecalculateParagraphs(); + textBody.ApplyAutoSize(); + + double delta = 0.001; + + //new day beckons is the largest line in the centered paragraph[0] + //Assert that the first line has been centered appropriately + Assert.AreEqual(9.890869140625d, textBody.Paragraphs[0].Runs[0].Bounds.Left, delta); + Assert.AreEqual(33.142333984375d, textBody.Paragraphs[0].Runs[1].Bounds.Left, delta); + Assert.AreEqual(59.509033203125d, textBody.Paragraphs[0].Runs[2].Bounds.Left, delta); + Assert.AreEqual(0d, textBody.Paragraphs[0].Runs[3].Bounds.Left); + + Assert.AreEqual(5.08, textBody.Paragraphs[1].Runs[0].Bounds.Left, delta); + Assert.AreEqual(0d, textBody.Paragraphs[1].Runs[1].Bounds.Left); + + //Assert that the second paragraph has been moved correctly + Assert.AreEqual(26.85546875d, textBody.Paragraphs[1].Bounds.Top); + GenerateSvgFile("textBodyAlignCenter", baseGroup.Bounds, baseGroup); + } + + [TestMethod] + public void SvgTextBodyTestRightAlignmentGenerated() + { + var baseGroup = GenerateGroupRenderItem(); + + var textBody = GenerateTextBody(baseGroup); + textBody.Paragraphs[0].AddText(" a\r\n new day beckons"); + textBody.Paragraphs[0].HorizontalAlignment = RenderItems.Shared.TextAlignment.Right; + + + textBody.Paragraphs[1].HorizontalAlignment = RenderItems.Shared.TextAlignment.Right; + textBody.Paragraphs[1].AddText("\r\n What fun, what fun!"); + + //Text was added to the paragraph above the last paragraph + //We must re-calculate where the next paragraph should be placed + textBody.RecalculateParagraphs(); + textBody.ApplyAutoSize(); + + double delta = 0.001; + + //Assert that the first line has been aligned correctly + Assert.AreEqual(19.78173828125d, textBody.Paragraphs[0].Runs[0].Bounds.Left, delta); + Assert.AreEqual(43.033203125d, textBody.Paragraphs[0].Runs[1].Bounds.Left, delta); + Assert.AreEqual(69.39990234375d, textBody.Paragraphs[0].Runs[2].Bounds.Left, delta); + Assert.AreEqual(0d, textBody.Paragraphs[0].Runs[3].Bounds.Left); + + Assert.AreEqual(10.16d, textBody.Paragraphs[1].Runs[0].Bounds.Left, delta); + Assert.AreEqual(0d, textBody.Paragraphs[1].Runs[1].Bounds.Left); + + GenerateSvgFile("textBodyAlignRight", baseGroup.Bounds, baseGroup); + } + + [TestMethod] + public void SvgTextBodyVerticalAlignmentGenerated() + { + var baseGroup = GenerateGroupRenderItem(); + + var textBody = GenerateTextBody(baseGroup); + textBody.Paragraphs[0].AddText(" a\r\n new day beckons"); + textBody.Paragraphs[1].AddText("\r\n What fun, what fun!"); + + //Text was added to the paragraph above the last paragraph + //We must re-calculate where the next paragraph should be placed + textBody.RecalculateParagraphs(); + textBody.ApplyAutoSize(); + + textBody.AutoSize = false; + textBody.Height = 500; + + textBody.Bounds.Top = 0; + textBody.VerticalAlignment = TextAnchoringType.Center; + textBody.Bounds.Top = textBody.GetAlignmentVertical(); + + double delta = 0.001; + + Assert.AreEqual(180.04052829742432d, textBody.Bounds.Top, delta); + + GenerateSvgFile("textBodyAlignVCenter", baseGroup.Bounds, baseGroup); + } + + [TestMethod] + public void SvgTextBodyVerticalAlignmentBottomGenerated() + { + var baseGroup = GenerateGroupRenderItem(); + + var textBody = GenerateTextBody(baseGroup); + textBody.Paragraphs[0].AddText(" a\r\n new day beckons"); + textBody.Paragraphs[1].AddText("\r\n What fun, what fun!"); + + //Text was added to the paragraph above the last paragraph + //We must re-calculate where the next paragraph should be placed + textBody.RecalculateParagraphs(); + textBody.ApplyAutoSize(); + + textBody.AutoSize = false; + textBody.Height = 500; + + textBody.Bounds.Top = 0; + textBody.VerticalAlignment = TextAnchoringType.Bottom; + textBody.Bounds.Top = textBody.GetAlignmentVertical(); + + double delta = 0.001; + Assert.AreEqual(430.04052829742432d, textBody.Bounds.Top, delta); + + GenerateSvgFile("textBodyAlignVBottom", baseGroup.Bounds, baseGroup); + } + + private RenderTextbox GenerateTextBox(out GroupRenderItem group) + { + group = GenerateGroupRenderItem(); + + var textbox = new RenderTextbox(group.Bounds, 500d, 500d); + var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + var rc = new RenderContext(() => engine); + textbox.TextBody = new SvgTextBodyRenderItem(rc, group.Bounds, true); + var paragraph = textbox.TextBody.AddParagraph("Hello"); + + paragraph.AddText(" There"); + + var rtItem = new RichTextFormatSimple("Second paragraph", "Archivo Narrow", 16f, true); + rtItem.FontColor = Color.DarkGreen; + var para2 = textbox.TextBody.AddParagraph(rtItem); + + textbox.Rectangle.FillColor = "#F9F6C4"; + + return textbox; + } + + [TestMethod] + public void BasicTextBox() + { + var textbox = GenerateTextBox(out GroupRenderItem group); + textbox.AppendRenderItems(group.RenderItems); + + double delta = 0.001; + + Assert.AreEqual(115.2d, textbox.Width, delta, $"textbox.Width was {textbox.Width}, not 107.952 as expected"); + Assert.AreEqual(34.979735851287842d, textbox.Height, delta, $"textbox.Height was {textbox.Height}, not 34.978 as expected"); + + GenerateSvgFile("BasicTextBox", group.Bounds, group); + } + + [TestMethod] + public void TextBoxWithMargins() + { + var textbox = GenerateTextBox(out GroupRenderItem group); + + double delta = 0.001; + + textbox.LeftMargin = 10d; + textbox.TopMargin = 10d; + + textbox.AppendRenderItems(group.RenderItems); + + //Assert local position unchanged + Assert.AreEqual(0d, textbox.TextBody.Left); + Assert.AreEqual(0d, textbox.TextBody.Top); + + //Assert global position changed + Assert.AreEqual(10d, textbox.TextBody.Bounds.Position.X); + Assert.AreEqual(10d, textbox.TextBody.Bounds.Position.Y); + + //Assert width and height changed by margins + Assert.AreEqual(125.2, textbox.Width, delta); + Assert.AreEqual(44.979735851287842d, textbox.Height, delta); + + + GenerateSvgFile("MarginTextBox", group.Bounds, group); + } + + [TestMethod] + public void TextBoxWithAllMargins() + { + var textbox = GenerateTextBox(out GroupRenderItem group); + + double delta = 0.001; + + textbox.LeftMargin = 10d; + textbox.TopMargin = 10d; + textbox.RightMargin = 10d; + textbox.BottomMargin = 10d; + + textbox.AppendRenderItems(group.RenderItems); + + //Assert width and height changed by margins + Assert.AreEqual(135.2d, textbox.Width, delta); + Assert.AreEqual(54.979735851287842d, textbox.Height, delta); + + GenerateSvgFile("AllMarginsTextBox", group.Bounds, group); + } + + + /// + /// TODO: Discuss. Should it really work like this? + /// There IS an argument to be made that margin should BE textbody position + /// At the same time then positioning in accordance with vertical aligment then becomes difficult + /// And might affect the margin + /// + [TestMethod] + public void TextBoxWithAllMarginsANDTextbodyChanged() + { + var textbox = GenerateTextBox(out GroupRenderItem group); + + double delta = 0.001; + + textbox.TextBody.AutoSize = true; + + textbox.TextBody.Left = 15d; + textbox.TextBody.Top = 15d; + + textbox.LeftMargin = 10d; + textbox.TopMargin = 10d; + textbox.RightMargin = 10d; + textbox.BottomMargin = 10d; + + textbox.AppendRenderItems(group.RenderItems); + + //Assert width and height changed by margins and textbody + Assert.AreEqual(150.2d, textbox.Width, delta); + Assert.AreEqual(69.979735851287842d, textbox.Height, delta); + + GenerateSvgFile("TextAnchor_TextBox", group.Bounds, group); + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.csproj b/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.csproj new file mode 100644 index 0000000000..20604a2971 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.csproj @@ -0,0 +1,37 @@ + + + + net8.0;net462 + latest + enable + enable + True + EPPlus.DrawingRenderer.Tests.snk + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.snk b/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.snk new file mode 100644 index 0000000000..bee7301e73 Binary files /dev/null and b/src/EPPlus.DrawingRenderer.Tests/EPPlus.DrawingRenderer.Tests.snk differ diff --git a/src/EPPlus.DrawingRenderer.Tests/GroupItemNewTest.cs b/src/EPPlus.DrawingRenderer.Tests/GroupItemNewTest.cs new file mode 100644 index 0000000000..757b5c14cd --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/GroupItemNewTest.cs @@ -0,0 +1,378 @@ +//using EPPlus.Export.ImageRenderer.ChartAreaRenderItems.SvgItem; +//using EPPlus.Export.ImageRenderer.Svg; +//using EPPlus.Graphics; +//using EPPlusImageRenderer.ChartAreaRenderItems; +//using System.Text; + +//namespace EPPlus.Export.ImageRenderer.Tests +//{ +// [TestClass] +// public class GroupItemNewTest : TestBase +// { +// //private void InitalizeTransformGroup() +// //{ +// // var baseBB = new BoundingBox(); + +// // //96x96 px +// // baseBB.Width = 72; +// // baseBB.Height = 72; + +// // var baseItem = new DrawingItemForTesting(baseBB); + +// // var groupItem = new SvgTransformGroup(baseItem, 9, 9); + +// // SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// // rectItem.FillColor = "red"; +// // rectItem.FillOpacity = 0.2d; + +// // rectItem.Width = 20; +// // rectItem.Height = 20; + +// // groupItem.AddChildItem(rectItem); + + +// // SvgRenderRectItem siblingItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); +// // siblingItem.FillColor = "blue"; +// // siblingItem.FillOpacity = 0.2d; + +// // siblingItem.Width = 20; +// // siblingItem.Height = 20; + +// // siblingItem.Bounds.Left = 20; +// // siblingItem.Bounds.Top = 20; + +// // groupItem.AddChildItem(siblingItem); +// //} + + +// [TestMethod] +// public void TransformGroupMoveCorrect() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var baseItem = new DrawingItemForTesting(baseBB); + +// var holderBB = new BoundingBox(); +// holderBB.Parent = baseItem.Bounds; + +// var groupItem = new SvgTransformGroup(baseItem, 9, 9); +// groupItem.Bounds.Parent = holderBB; + +// SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// rectItem.FillColor = "red"; +// rectItem.FillOpacity = 0.2d; + +// rectItem.Width = 20; +// rectItem.Height = 20; + +// groupItem.AddChildItem(rectItem); + + +// SvgRenderRectItem siblingItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); +// siblingItem.FillColor = "blue"; +// siblingItem.FillOpacity = 0.2d; + +// siblingItem.Width = 20; +// siblingItem.Height = 20; + +// siblingItem.Bounds.Left = 20; +// siblingItem.Bounds.Top = 20; + +// groupItem.AddChildItem(siblingItem); + +// var worldCoordinatesRectBefore = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(9, worldCoordinatesRectBefore.X); +// Assert.AreEqual(9, worldCoordinatesRectBefore.Y); + +// var worldCoordinatesSibBefore = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(29, worldCoordinatesSibBefore.X); +// Assert.AreEqual(29, worldCoordinatesSibBefore.Y); + +// groupItem.Bounds.Left = 18; +// groupItem.Bounds.Top = 18; + +// var worldCoordinatesRect = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(18, worldCoordinatesRect.X); +// Assert.AreEqual(18, worldCoordinatesRect.Y); + +// var worldCoordinatesSib = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(38, worldCoordinatesSib.X); +// Assert.AreEqual(38, worldCoordinatesSib.Y); + +// groupItem.Scale = new EPPlusImageRenderer.Coordinate(0.5d, 0.5d); + +// groupItem.Bounds.Left = 0; +// groupItem.Bounds.Top = 0; + +// //groupItem.Bounds.Left = 0; +// //groupItem.Bounds.Top = 0; + +// rectItem.Bounds.Left = 18; +// rectItem.Bounds.Top = 18; + +// var unchangedVector = rectItem.Bounds.GetWorldCoordinates(); + +// ////Graphics.Math.Matrix3x3 scaleHalfMatrix +// var worldCoordinatesRectAfterScale = rectItem.Bounds.Position; +// Assert.AreEqual(9, worldCoordinatesRectAfterScale.X); +// Assert.AreEqual(9, worldCoordinatesRectAfterScale.Y); + +// var worldCoordinatesSibAfterScale = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(10, worldCoordinatesSibAfterScale.X); +// Assert.AreEqual(10, worldCoordinatesSibAfterScale.Y); + + +// var sb = new StringBuilder(); + +// baseItem.ChartAreaRenderItems.Add(groupItem); + +// baseItem.Render(sb); +// var svgString = sb.ToString(); + +// SaveTextFileToWorkbook($"svg\\StandAloneTranslateGroup.svg", svgString); +// } + + +// [TestMethod] +// public void GroupInGroupMoveCorrect2() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var baseItem = new DrawingItemForTesting(baseBB); + +// var groupItem = new SvgGroupItemNew(baseItem, 5, 15); + +// SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// groupItem.AddChildItem(rectItem); + +// rectItem.FillColor = "red"; +// rectItem.FillOpacity = 0.2d; + +// rectItem.Width = 20; +// rectItem.Height = 20; + +// groupItem.TranslationOffset.Left = 5; +// groupItem.TranslationOffset.Top = 6; + +// var leftGlobal = groupItem.TranslationOffset.Position.X; +// var topGlobal = groupItem.TranslationOffset.Position.Y; +// var leftGlobalUnder = groupItem.Bounds.Position.X; +// var topGlobalUnder = groupItem.Bounds.Position.Y; + +// Assert.AreEqual(10, leftGlobalUnder); +// Assert.AreEqual(21, topGlobalUnder); +// } + +// [TestMethod] +// public void GroupInGroupMoveCorrect() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var baseItem = new DrawingItemForTesting(baseBB); + +// var groupItem = new SvgGroupItemNew(baseItem, 9, 9); + +// var subItem = new SvgGroupItemNew(baseItem, 9, 9); +// subItem.TranslationOffset.Parent = groupItem.TranslationOffset; +// groupItem.AddChildItem(subItem); + +// SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// rectItem.FillColor = "red"; +// rectItem.FillOpacity = 0.2d; + +// rectItem.Width = 20; +// rectItem.Height = 20; + +// subItem.AddChildItem(rectItem); + +// SvgRenderRectItem siblingItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); +// siblingItem.FillColor = "blue"; +// siblingItem.FillOpacity = 0.2d; + +// siblingItem.Width = 20; +// siblingItem.Height = 20; + +// siblingItem.Bounds.Left = 20; +// siblingItem.Bounds.Top = 20; + +// subItem.AddChildItem(siblingItem); + +// var worldCoordinatesRectBefore = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(18, worldCoordinatesRectBefore.X); +// Assert.AreEqual(18, worldCoordinatesRectBefore.Y); + +// var worldCoordinatesSibBefore = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(38, worldCoordinatesSibBefore.X); +// Assert.AreEqual(38, worldCoordinatesSibBefore.Y); + +// subItem.TranslationOffset.Left = 9; +// subItem.TranslationOffset.Top = 9; + +// var worldCoordinatesRect = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(27, worldCoordinatesRect.X); +// Assert.AreEqual(27, worldCoordinatesRect.Y); + +// var worldCoordinatesSib = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(47, worldCoordinatesSib.X); +// Assert.AreEqual(47, worldCoordinatesSib.Y); + +// var sb = new StringBuilder(); + +// baseItem.ChartAreaRenderItems.Add(groupItem); + +// baseItem.Render(sb); +// var svgString = sb.ToString(); + +// SaveTextFileToWorkbook($"svg\\subItemInSubItem.svg", svgString); +// } + +// [TestMethod] +// public void GrpPosTranslateChildren() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var baseItem = new DrawingItemForTesting(baseBB); + +// var groupItem = new SvgGroupItemNew(baseItem, 9, 9); + +// SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// rectItem.FillColor = "red"; +// rectItem.FillOpacity = 0.2d; + +// rectItem.Width = 20; +// rectItem.Height = 20; + +// groupItem.AddChildItem(rectItem); + + +// SvgRenderRectItem siblingItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); +// siblingItem.FillColor = "blue"; +// siblingItem.FillOpacity = 0.2d; + +// siblingItem.Width = 20; +// siblingItem.Height = 20; + +// siblingItem.Bounds.Left = 20; +// siblingItem.Bounds.Top = 20; + +// groupItem.AddChildItem(siblingItem); + +// var worldCoordinatesRectBefore = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(9, worldCoordinatesRectBefore.X); +// Assert.AreEqual(9, worldCoordinatesRectBefore.Y); + +// var worldCoordinatesSibBefore = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(29, worldCoordinatesSibBefore.X); +// Assert.AreEqual(29, worldCoordinatesSibBefore.Y); + +// groupItem.TranslationOffset.Left = 9; +// groupItem.TranslationOffset.Top = 9; + +// var worldCoordinatesRect = rectItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(18, worldCoordinatesRect.X); +// Assert.AreEqual(18, worldCoordinatesRect.Y); + +// var worldCoordinatesSib = siblingItem.Bounds.GetWorldCoordinates(); +// Assert.AreEqual(38, worldCoordinatesSib.X); +// Assert.AreEqual(38, worldCoordinatesSib.Y); + +// var gLeft = groupItem.Bounds.Position.X; +// var gTop = groupItem.Bounds.Position.Y; + +// var sb = new StringBuilder(); + +// baseItem.ChartAreaRenderItems.Add(groupItem); + +// baseItem.Render(sb); +// var svgString = sb.ToString(); + +// SaveTextFileToWorkbook($"svg\\StandAloneTestGroup.svg", svgString); +// } + +// [TestMethod] +// public void RotateTwoChildren() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var baseItem = new DrawingItemForTesting(baseBB); + +// BoundingBox parent = new BoundingBox(); + +// var groupItem = new SvgGroupItemNew(baseItem, parent, 45); + +// groupItem.TranslationOffset.Left = 10; +// groupItem.TranslationOffset.Top = 10; + +// SvgRenderRectItem rectItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); + +// rectItem.FillColor = "red"; +// rectItem.FillOpacity = 0.2d; + +// rectItem.Width = 20; +// rectItem.Height = 20; + +// groupItem.AddChildItem(rectItem); + + +// SvgRenderRectItem siblingItem = new SvgRenderRectItem(baseItem, groupItem.Bounds); +// siblingItem.FillColor = "blue"; +// siblingItem.FillOpacity = 0.2d; + +// siblingItem.Width = 20; +// siblingItem.Height = 20; + +// siblingItem.Bounds.Left = 20; +// siblingItem.Bounds.Top = 20; + +// groupItem.AddChildItem(siblingItem); + +// groupItem.SetRotationPointToCenterOfGroup(); + +// SvgRenderRectItem centerOfGroupMarker = new SvgRenderRectItem(baseItem, baseItem.Bounds); +// centerOfGroupMarker.FillColor = "green"; +// centerOfGroupMarker.FillOpacity = 0.8d; + +// centerOfGroupMarker.Width = 6; +// centerOfGroupMarker.Height = 6; + +// centerOfGroupMarker.Left = 30 - (centerOfGroupMarker.Width / 2); +// centerOfGroupMarker.Top = 30 - (centerOfGroupMarker.Height / 2); + +// baseItem.ChartAreaRenderItems.Add(centerOfGroupMarker); + +// var sb = new StringBuilder(); + +// baseItem.ChartAreaRenderItems.Add(groupItem); + +// baseItem.Render(sb); +// var svgString = sb.ToString(); + +// SaveTextFileToWorkbook($"svg\\TestGroupRotated.svg", svgString); +// } +// } +//} diff --git a/src/EPPlus.DrawingRenderer.Tests/MSTestSettings.cs b/src/EPPlus.DrawingRenderer.Tests/MSTestSettings.cs new file mode 100644 index 0000000000..aaf278c844 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs b/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs new file mode 100644 index 0000000000..190b8d847e --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs @@ -0,0 +1,78 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.ShapeDefinitions; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; + +namespace TestProject1 +{ + [TestClass] + public sealed class PresetShapeDefinitionTests + { + [TestMethod] + public async Task LoadPreset() + { + var psd = PresetShapeDefinitions.ShapeDefinitions; + Assert.AreEqual(187, psd.Count); + + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var shape = ws.Drawings.AddShape("Rect1", OfficeOpenXml.Drawing.eShapeStyle.Rect); + + PresetShapeDefinitions.ShapeDefinitions[(ShapeStyle)shape.Style].Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); + await p.SaveAsAsync("c:\\temp\\rect.xlsx"); + } + } + + [TestMethod] + public void MathMultiplyTest() + { + ExcelPackage.License.SetNonCommercialPersonal("EPPLUS"); + var shDef = PresetShapeDefinitions.ShapeDefinitions[ShapeStyle.MathMultiply]; + + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("ws"); + var shape = ws.Drawings.AddShape("mMult", eShapeStyle.MathMultiply); + shDef.Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); + } + } + + [TestMethod] + public void CurvedDownArrow() + { + ExcelPackage.License.SetNonCommercialPersonal("EPPLUS"); + var shDef = PresetShapeDefinitions.ShapeDefinitions[ShapeStyle.CurvedDownArrow]; + + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("ws"); + var shape = ws.Drawings.AddShape("mMult", eShapeStyle.CurvedDownArrow); + shape.SetSize(100, 100); + + shDef.Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); + + + //shDef._calculatedValues + + } + } + [TestMethod] + public void BlockArc() + { + ExcelPackage.License.SetNonCommercialPersonal("EPPLUS"); + var shDef = PresetShapeDefinitions.ShapeDefinitions[ShapeStyle.BlockArc]; + + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("ws"); + var shape = ws.Drawings.AddShape("mMult", eShapeStyle.BlockArc); + shape.SetSize(100, 100); + + shDef.Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); + //shDef._calculatedValues + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs b/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs new file mode 100644 index 0000000000..d56766ae27 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs @@ -0,0 +1,720 @@ +using EPPlus.Fonts.OpenType; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Style; +using System.Diagnostics; +using System.Drawing; +using System.Reflection; +using System.Text; +using System.Xml; +using TypeConv = OfficeOpenXml.Utils.TypeConversion; + +namespace EPPlus.Export.ImageRenderer.Tests.Shape +{ + [TestClass] + public sealed class ShapeToSvgTests : TestBase + { + + [TestInitialize] + public void Initialize() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + } + + private OpenTypeFontEngine DefaultFontEngine + { + get { return new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); } + } + + private ExcelPackage GetPackage() + { + var p = new ExcelPackage(); + p.Workbook.UseFontEngine(DefaultFontEngine); + return p; + } + + [TestMethod] + public void GroupFill() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + using (var p = OpenTemplatePackage("GroupFill.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var drawings = ws.Drawings; + + int ix = 0; + + foreach (var drawing in drawings) + { + if (drawing is ExcelGroupShape) + { + var gShape = (ExcelGroupShape)drawing; + var gDrawings = gShape.Drawings; + foreach (var gDrawing in gDrawings) + { + SaveTextFileToWorkbook($"svg\\GroupFill{ix++}.svg", gDrawing.ToSvg()); + } + } + else + { + var shapeCast = drawing.As.Shape; + var filltype = shapeCast.Fill.Style; + + var svg = drawing.ToSvg(); + SaveTextFileToWorkbook($"svg\\GroupFill{ix++}.svg", svg); + } + } + SaveAndCleanup(p); + } + } + + + + [TestMethod] + public void Rect() + { + + using (var p = OpenPackage("svg/rect.xlsx", true)) + { + p.Workbook.UseFontEngine(DefaultFontEngine); + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Rect); + d.Text = "Rectangle Rectangle Rectangle Rectangle"; + d.TextAlignment = OfficeOpenXml.Drawing.eTextAlignment.Left; + d.TextAnchoring = OfficeOpenXml.Drawing.eTextAnchoringType.Bottom; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\rect.svg", svg); + SaveAndCleanup(p); + } + } + + [TestMethod] + public void AddShapeWithPatternFill() + { + using (var p = OpenTemplatePackage("ShapeWithPattern.xlsx")) + { + p.Workbook.UseFontEngine(DefaultFontEngine); + var ws = p.Workbook.Worksheets[0]; + + var myShape = ws.Drawings[0].As.Shape; + + var svg = myShape.ToSvg(); + + SaveTextFileToWorkbook("svg\\ShapeWithPattern.svg", svg); + SaveAndCleanup(p); + } + } + + + [TestMethod] + public void RoundRect() + { + using (var p = GetPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", eShapeStyle.RoundRect); + + d.TextAlignment = OfficeOpenXml.Drawing.eTextAlignment.Left; + d.TextAnchoring = OfficeOpenXml.Drawing.eTextAnchoringType.Bottom; + d.Text = "Rectangle Rectangle Rectangle Rectangle"; + + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\Roundrect.svg", svg); + SaveWorkbook("svgRoundRectdrawing.xlsx", p); + } + } + [TestMethod] + public void Triangle() + { + + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Triangle); + d.Text = "Test"; + d.TextAlignment = OfficeOpenXml.Drawing.eTextAlignment.Center; + d.TextAnchoring = OfficeOpenXml.Drawing.eTextAnchoringType.Center; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\Triangle.svg", svg); + SaveWorkbook("svgTriangleDrawing.xlsx", p); + } + } + [TestMethod] + public void RightArrow() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.RightArrow); + d.SetSize(100, 100); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\RightArrow.svg", svg); + SaveWorkbook("svgRightArrowDrawing.xlsx", p); + } + } + [TestMethod] + public void SmileyFace() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.SmileyFace); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\SmileyFace.svg", svg); + SaveWorkbook("svgSmileyFace.xlsx", p); + } + } + [TestMethod] + public void VerticalScroll() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.VerticalScroll); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\VerticalScroll.svg", svg); + SaveWorkbook("svgVerticalScroll.xlsx", p); + } + } + [TestMethod] + public void CloudCallout() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.CloudCallout); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\CloudCallout.svg", svg); + SaveWorkbook("svgCloudCallout.xlsx", p); + } + } + [TestMethod] + public void IrregularSeal2() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.IrregularSeal2); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\IrregularSeal2.svg", svg); + SaveWorkbook("IrregularSeal2.xlsx", p); + } + } + [TestMethod] + public void LightningBolt() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.LightningBolt); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\LightningBolt.svg", svg); + SaveWorkbook("svgLightningBolt.xlsx", p); + } + } + [TestMethod] + public void FlowChartMagneticTape() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.FlowChartMagneticTape); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\FlowChartMagneticTape.svg", svg); + SaveWorkbook("svgFlowChartMagneticTape.xlsx", p); + } + } + [TestMethod] + public void MathNotEqual() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.MathNotEqual); + d.SetSize(800, 800); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\MathNotEqual.svg", svg); + SaveWorkbook("svgMathNotEqual.xlsx", p); + } + } + [TestMethod] + public void Sun() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Sun); + + d.SetSize(800, 800); + d.Fill.Color = Color.Orange; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\Sun.svg", svg); + SaveWorkbook("svgSun.xlsx", p); + } + } + [TestMethod] + public void Ellipse() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Ellipse); + + d.SetSize(800, 800); + d.Fill.Color = Color.Orange; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\Ellipse.svg", svg); + SaveWorkbook("svgEllipse.xlsx", p); + } + } + [TestMethod] + public void Heart() + { + using (var p = GetPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Heart); + + d.SetSize(800, 800); + d.Fill.Color = Color.Red; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\Heart.svg", svg); + SaveWorkbook("svgHeart.xlsx", p); + } + } + [TestMethod] + public void BevelRed() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Bevel); + + d.SetSize(804, 804); + d.Fill.Color = Color.Red; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\bevelred.svg", svg); + SaveWorkbook("svgBevelred.xlsx", p); + } + } + [TestMethod] + public void Bevel() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", OfficeOpenXml.Drawing.eShapeStyle.Bevel); + + d.SetSize(804, 804); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\bevel.svg", svg); + SaveWorkbook("svgBevel.xlsx", p); + } + } + + [TestMethod] + public void LeftBracket() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", eShapeStyle.LeftBracket); + + d.SetSize(804, 804); + d.Fill.Style = eFillStyle.NoFill; + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\LeftBracket.svg", svg); + SaveWorkbook("LeftBracket.xlsx", p); + } + } + [TestMethod] + public void CalloutQuadArrow() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", eShapeStyle.QuadArrowCallout); + + d.SetSize(804, 200); + var svg = d.ToSvg(); + SaveTextFileToWorkbook("svg\\QuadArrowCallout.svg", svg); + SaveWorkbook("QuadArrowCallout.xlsx", p); + } + } + [TestMethod] + public void ActionButtonHome() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", eShapeStyle.ActionButtonHome); + + d.SetSize(804, 804); + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\ActionButtonHome.svg", svg); + SaveWorkbook("ActionButtonHome.xlsx", p); + } + } + [TestMethod] + public void ActionButtonMovie() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Sheet1"); + var d = ws.Drawings.AddShape("Shape1", eShapeStyle.ActionButtonMovie); + + d.SetSize(804, 804); + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\ActionButtonMovie.svg", svg); + SaveWorkbook("ActionButtonMovie.xlsx", p); + } + } + [TestMethod] + public void CustomPath() + { + using (var p = OpenTemplatePackage(@"svg\CustPath.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var d = ws.Drawings[0].As.Shape; + //Assert.AreEqual(1, d.CustomGeom.DrawingPaths.Count); + //d.Textbox = "GetGetRectangle GetGetRectangle GetGetRectangle GetGetRectangle"; + //d.TextAlignment = OfficeOpenXml.Drawing.TextAlignment.Left; + //d.TextAnchoring = OfficeOpenXml.Drawing.eTextAnchoringType.Bottom; + //var svg = renderer.RenderDrawingToSvg(d); + //SaveTextFileToWorkbook("CustomDrawing1.svg", svg); + + var d = ws.Drawings[0].As.Shape; + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\CustomDrawing2.svg", svg); + + //SaveWorkbook("svgdrawing.xlsx"); + } + } + + + [TestMethod] + public void GenerateAllShapes() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Shapes"); + int y = 100, i = 1; + foreach (eShapeStyle style in Enum.GetValues(typeof(eShapeStyle))) + { + if (style == eShapeStyle.CustomShape) continue; + var shape = ws.Drawings.AddShape(style.ToString(), style); + shape.Text = style.ToString(); + Assert.AreEqual(eDrawingType.Shape, shape.DrawingType); + shape.SetPosition(y, 100); + shape.SetSize(600, 600); + y += 700; + i++; + } + SaveWorkbook("shapes.xlsx", p); + } + } + + [TestMethod] + public void TestShapes() + { + using (var p = OpenTemplatePackage("margins.xlsx")) + { + var drawings = p.Workbook.Worksheets[0].Drawings; + var textbody = drawings[0].As.Shape.TextBody; + + var insertCM = textbody.LeftInsert.Value * 0.0352777778; + + Assert.AreEqual(0.3d, insertCM, 0.00001); + } + } + [TestMethod] + public void GenerateSvgForGradientFilledShapes() + { + using (var p = OpenTemplatePackage("GradientFillShapes.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + int ix = 1; + + //var d = ws.Drawings[7]; + //var svg = renderer.RenderDrawingToSvg(d); + //File.WriteAllText($"c:\\temp\\{d.Name}-{ix}.svg", svg); + + foreach (var d in ws.Drawings) + { + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\{d.Name}-{ix}.svg", svg); + ix++; + } + } + } + [TestMethod] + public void GenerateSvgForGradientRadialFilledShapes() + { + using (var p = OpenTemplatePackage("GradiantRadial.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var d = ws.Drawings[5]; + //var svg = renderer.RenderDrawingToSvg(d); + //File.WriteAllText($"c:\\temp\\{d.Name}-{5}.svg", svg); + + int ix = 1; + + foreach (var d in ws.Drawings) + { + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\{d.Name}-{ix}.svg", svg); + ix++; + } + } + } + [TestMethod] + public void GenerateSvgForPatternFilledShapes() + { + using (var p = OpenTemplatePackage("PatternFills.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + int ix = 1; + + foreach (ExcelShape d in ws.Drawings) + { + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\Pattern-{d.Fill.PatternFill.PatternType}-{ix}.svg", svg); + ix++; + } + } + } + [TestMethod] + public void GenerateSvgForBlipFillShapes() + { + using (var p = OpenTemplatePackage("BlipFills.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + int ix = 1; + + foreach (ExcelShape d in ws.Drawings) + { + var svg = d.ToSvg(); + SaveSvg($"Blip{ix}.svg", svg); + ix++; + } + } + } + + + [TestMethod] + public void GenerateSvgForCircle() + { + using (var p = OpenTemplatePackage("GradientRadialVerifyCircle.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var svg = renderer.RenderDrawingToSvg(ws.Drawings[1]); + //File.WriteAllText($"c:\\temp\\ChartForSvg{1}.svg", svg); + + int ix = 1; + + foreach (ExcelShape d in ws.Drawings) + { + var svg = d.ToSvg(); + SaveTextFileToWorkbook($"svg\\DrawForSvg{ix}.svg", svg); + ix++; + } + } + } + + [TestMethod] + public void SuperScriptShape() + { + using (var p = OpenTemplatePackage("Superscript.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\LineChartForSvg_Single{ix++}.svg", svg); + var ix = 0; + foreach (var c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\ss{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void SuperAndSubScript() + { + using (var p = OpenTemplatePackage("SuperAndSubScript.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + var currShape = ws.Drawings[0]; + + var svg = currShape.ToSvg(); + SaveTextFileToWorkbook("svg\\SuperAndSubScript.svg", svg); + } + } + + [TestMethod] + public void OpenRightAligned() + { + using (var p = OpenTemplatePackage("SimpleChartRightAlign.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0]; + + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\SimplestChartRightAlign.svg", svg); + } + } + [TestMethod] + public void TestStyling() + { + using (var p = OpenTemplatePackage("MyCellsAdvanced.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var myCell = ws.Cells["B3"]; + var myCellStyle = myCell.Style; + var fillStyle = myCell.Style.Fill; + var fontColor = myCell.Style.Font.Color; + + var bgRgb = myCell.Style.Fill.BackgroundColor.Rgb; + var bgFillCol = myCell.Style.Fill.PatternColor.Rgb; + + var myOtherCell = ws.Cells["B2"]; + + var myShape = ws.Drawings[0].As.Shape; + var myRichtext = myShape.RichText; + var firstDefault = myShape.TextBody.Paragraphs.FirstDefaultRunProperties; + + var firstPara = myShape.TextBody.Paragraphs[0]; + var defRun = firstPara.DefaultRunProperties; + + var secondPara = myShape.TextBody.Paragraphs[1]; + var secondDefRun = secondPara.DefaultRunProperties; + } + } + + [TestMethod] + public void GenerateShapeCenteredParagraph() + { + using (var p = OpenPackage("ShapeTestCentered.xlsx",true)) + { + var sheet = p.Workbook.Worksheets.Add("ShapeSheet"); + + var _currentShape = sheet.Drawings.AddShape("CubeTest", eShapeStyle.Cube); + + _currentShape.SetPixelWidth(300d); + _currentShape.SetPixelHeight(300d); + + _currentShape.Fill.Style = eFillStyle.SolidFill; + _currentShape.Fill.Color = System.Drawing.Color.BlueViolet; + _currentShape.Font.Color = System.Drawing.Color.Goldenrod; + + _currentShape.TextBody.TopInsert = 0; + _currentShape.TextBody.BottomInsert = 0; + _currentShape.TextBody.RightInsert = 0; + _currentShape.TextBody.LeftInsert = 0; + + var para1 = _currentShape.TextBody.Paragraphs.Add("TextBodySvg\r\na"); + //var test = _currentShape.TextBody.AnchorCenter; + + para1.LeftMargin = 5; + _currentShape.TextBody.TopInsert = 10; + + var para2 = _currentShape.TextBody.Paragraphs.Add("TextBox2"); + para2.TextRuns[0].FontItalic = true; + para2.TextRuns[0].FontBold = true; + para2.TextRuns.Add("ra underline").FontUnderLine = eUnderLineType.Dash; + para2.TextRuns.Add("La Strike").FontStrike = eStrikeType.Single; + var tRun1 = para2.TextRuns.Add("Goudy size 16"); + tRun1.SetFromFont("Goudy Stout", 16); + + _currentShape.TextBody.Paragraphs[0].HorizontalAlignment = eTextAlignment.Center; + + _currentShape.TextAnchoring = eTextAnchoringType.Top; + + //var smiley = "\ud83d\ude03"; + + tRun1.Fill.Color = System.Drawing.Color.IndianRed; + var tRun2 = para2.TextRuns.Add("SvgSize 24"); + tRun2.FontSize = 24; + + //_currentShape.TextAnchoring = eTextAnchoringType.Center; + + _currentShape.TextBody.HorizontalTextOverflow = eTextHorizontalOverflow.Clip; + _currentShape.TextBody.VerticalTextOverflow = eTextVerticalOverflow.Clip; + + + //SetFillColor(_currentShape.Fill, txtFillColor.Text); + //SetFillColor(_currentShape.Border.Fill, txtBorderColor.Text); + + var aFont = _currentShape.Font; + var paragraph0 = _currentShape.TextBody.Paragraphs[0]; + + _currentShape.GetSizeInPixels(out int testWidth, out int testHeight); + + var svg = _currentShape.ToSvg(); + SaveTextFileToWorkbook("svg\\centeredParagraph.svg", svg); + SaveAndCleanup(p); + } + } + + [TestMethod] + public void ChartAndShapeGreen() + { + using (var p = OpenTemplatePackage("ShapeAndChartTestGreen.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + //var ix = 1; + //var c = ws.Drawings[ix]; + //var svg = renderer.RenderDrawingToSvg(c); + //SaveTextFileToWorkbook($"svg\\LineChartForSvg_Single{ix++}.svg", svg); + var ix = 0; + foreach (var c in ws.Drawings) + { + var svg = c.ToSvg(); + SaveTextFileToWorkbook($"svg\\TestGreen{ix++}.svg", svg); + } + } + } + + [TestMethod] + public void CreateChartsWithDifferentSize() + { + using (var p = OpenPackage("ChartWithDifferentSizes.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("Chart1"); + + LoadItemData(ws); + var chart1 = ws.Drawings.AddChart("chart1", eChartType.Line); + chart1.Title.Text = "This is a very long title that should be wrapped into multiple lines."; + chart1.Title.Font.Size = 32; + chart1.Series.Add(ws.Cells["O2:O11"], ws.Cells["N2:N10"]); + chart1.SetPosition(2, 0, 1, 0); + chart1.SetSize(400, 400); + + var chart2 = ws.Drawings.AddChart("chart2", eChartType.ColumnClustered); + chart2.Title.Text = "This is a very long title that should be wrapped into multiple lines."; + chart2.Title.Font.Size = 32; + chart2.Series.Add(ws.Cells["O2:O11"], ws.Cells["N2:N10"]); + chart2.SetPosition(25, 0, 1, 0); + chart2.SetSize(400, 800); + + var chart3 = ws.Drawings.AddChart("chart3", eChartType.BarClustered); + chart3.Title.Text = "This is a very long title that should be wrapped into multiple lines."; + chart3.Title.Font.Size = 32; + chart3.Series.Add(ws.Cells["O2:O11"], ws.Cells["N2:N10"]); + chart3.SetPosition(25, 0, 8, 0); + chart3.SetSize(800, 400); + + SaveAndCleanup(p); + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/StyleTests.cs b/src/EPPlus.DrawingRenderer.Tests/StyleTests.cs new file mode 100644 index 0000000000..89b24c08fd --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/StyleTests.cs @@ -0,0 +1,244 @@ +using OfficeOpenXml; +using System.Drawing; +using System.Linq; + +namespace EPPlus.Export.ImageRenderer.Tests +{ + [TestClass] + public class StyleTests : TestBase + { + + [TestMethod] + public void BaseThemeChartStyle() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + using (var p = OpenTemplatePackage("baseThemeChartStyle.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0].As.Chart.LineChart; + var svg = c.ToSvg(); + //var renderer = new EPPlusImageRenderer.ImageRenderer(); + //var svg = renderer.RenderDrawingToSvg(c); + SaveTextFileToWorkbook($"svg\\baseThemeChartStyle.svg", svg); + } + } + + [TestMethod] + public void BaseThemeChartStyle2() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + using (var p = OpenTemplatePackage("baseThemeChartStyle2.xlsx")) + { + var c = p.Workbook.Worksheets[0].Drawings[0].As.Chart.LineChart; + var svg = c.ToSvg(); + //var renderer = new EPPlusImageRenderer.ImageRenderer(); + //var svg = renderer.RenderDrawingToSvg(c); + SaveTextFileToWorkbook($"svg\\baseThemeChartStyle2.svg", svg); + } + } + [TestMethod] + public void ChangeSeriesTest() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + using (var p = OpenTemplatePackage("MyLineIonThemeExcel.xlsx")) + { + var wbStyles = p.Workbook.Styles; + var simpleChart = p.Workbook.Worksheets[0].Drawings[0].As.Chart.LineChart; + + //simpleChart.StyleManager.ApplyStyles(); + + p.Workbook.Worksheets[0].Cells["A3"].Value = 15; + p.Workbook.Worksheets[0].Cells["B3"].Value = 2; + p.Workbook.Worksheets[0].Cells["C3"].Value = 25; + + var range = p.Workbook.Worksheets[0].Cells["A3:C3"]; + + var series = simpleChart.Series.Add(range); + series.Header = "MySeries"; + + simpleChart.Title.Text = "Hello"; + + //simpleChart.StyleManager.ApplyStyles(); + //var chartDefaultStyle = simpleChart.StyleManager.Style; + + //simpleChart.StyleManager.Style.Title.FontReference.Color.SetPresetColor(Color.CornflowerBlue); + + ////Highest order of styling if datapoint does not exist + ////simpleChart.StyleManager.Style.DeleteAllNode("cs:dataPointLine"); + //simpleChart.StyleManager.Style.DataPointLine.BorderReference.Color.SetPresetColor(Color.Green); + + //simpleChart.StyleManager.ApplyStyles(); + + var svg = simpleChart.ToSvg(); + SaveTextFileToWorkbook($"svg\\ChangeSeriesStyleTest.svg", svg); + p.SaveAs(GetOutputFile("", "ChangeSeriesStyleTest.xlsx")); + //SaveAndCleanup(p); + } + } + + [TestMethod] + public void ExtractThemeStyleWorks() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + using (var p = OpenTemplatePackage("MyLineIonThemeExcel.xlsx")) + { + var wbStyles = p.Workbook.Styles; + var simpleChart = p.Workbook.Worksheets[0].Drawings[0].As.Chart.LineChart; + + //p.Workbook.Worksheets[0].Cells["A3"].Value = 15; + //p.Workbook.Worksheets[0].Cells["B3"].Value = 2; + //p.Workbook.Worksheets[0].Cells["C3"].Value = 25; + + //var range = p.Workbook.Worksheets[0].Cells["A3:C3"]; + + //var series = simpleChart.Series.Add(range); + //series.Header = "MySeries"; + + simpleChart.Title.Text = "Hello"; + + //p.Workbook.ThemeManager.CurrentTheme.ColorScheme.Accent1.SetPresetColor(Color.DarkGoldenrod); + + var chartDefaultStyle = simpleChart.StyleManager.Style; + //simpleChart.StyleManager.SetChartStyle(OfficeOpenXml.Drawing.Chart.Style.ePresetChartStyle.LineChartStyle2); + ////var fillStyle = simpleChart.StyleManager.Style.DataPointLine.Border.Fill; + + //var svgFill = new SvgFill(fillStyle); + //var fillTranslator = new SvgFillTranslator(svgFill); + + //var context = new TranslatorContext(new HtmlRangeExportSettings()); + + //var declarations = fillTranslator.GenerateDeclarationList(context); + + //var styleClass = new CssRule("Style", 0); + + //context.SetTranslator(fillTranslator); + //context.AddDeclarations(styleClass); + + //simpleChart.StyleManager.ApplyStyles(); + + //chartDefaultStyle.DataPointLine.FillReference.Color + //simpleChart.Title.Font.Color = Color.CornflowerBlue; + simpleChart.StyleManager.Style.Title.FontReference.Color.SetPresetColor(Color.CornflowerBlue); + + //Highest order of styling if datapoint does not exist + //simpleChart.StyleManager.Style.DeleteAllNode("cs:dataPointLine"); + simpleChart.StyleManager.Style.DataPointLine.BorderReference.Color.SetPresetColor(Color.Green); + + // + //var currBorderFill = simpleChart.StyleManager.Style.DataPointLine.Border.Fill; + //simpleChart.StyleManager.Style.DataPointLine.Border.Fill.DeleteNode(path); + //simpleChart.StyleManager.Style.DataPointLine.Border.Fill.Color = Color.Red; + //simpleChart.StyleManager.Style.DataPointLine.Fill.Color = Color.Green; + + //simpleChart.StyleManager.Style.DataPoint.Fill.Color = Color.Yellow; + //simpleChart.StyleManager.Style.DataPoint.Border.Fill.Color = Color.Magenta; + + simpleChart.StyleManager.ApplyStyles(); + + //simpleChart.Title.TextBody.Paragraphs[0].TextRuns[0].Fill.Color = Color.CornflowerBlue; + + var svg = simpleChart.ToSvg(); + SaveTextFileToWorkbook($"svg\\MyLineIonThemeExcel2.svg", svg); + + //var serLine = chartDefaultStyle.SeriesLine; + //var lineElement = serLine.Border.LineElement; + //var serLineFillRef = serLine.Border.Fill; + //var myFillRef = chartDefaultStyle.Title.FillReference; + //var myFill = chartDefaultStyle.Title.Fill; + //var myLine = chartDefaultStyle.Title.Border; + + SaveAndCleanup(p); + } + + } + + [TestMethod] + public void ExtractThemeStyleWorksDataLine() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + using (var p = OpenTemplatePackage("MyLineIonThemeExcel.xlsx")) + { + var wbStyles = p.Workbook.Styles; + var simpleChart = p.Workbook.Worksheets[0].Drawings[0].As.Chart.LineChart; + + simpleChart.Title.Text = "Hello"; + + //var chartDefaultStyle = simpleChart.StyleManager.Style; + //simpleChart.StyleManager.ApplyStyles(); + + //simpleChart.Title.TextBody.Paragraphs[0].TextRuns[0].Fill.Color = Color.CornflowerBlue; + + //var svg = simpleChart.ToSvg(); + //SaveTextFileToWorkbook($"svg\\MyLineIonThemeExcelChangeOnlyTitle.svg", svg); + + var fontSize = simpleChart.Title.Font.Size; + + Assert.AreEqual(simpleChart.Title.Font.Size, 14d); + var paragraphPropeties = simpleChart.Title.GetNode("c:txPr/a:p/a:pPr"); + var paragraphPropertiesRich = simpleChart.Title.GetNode("c:tx/c:rich/a:p/a:pPr"); + Assert.AreEqual(paragraphPropeties.InnerXml, paragraphPropertiesRich.InnerXml); + + SaveAndCleanup(p); + } + + } + + [TestMethod] + public void TextRunIsStyledButNotTitleFont() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + var chartName = "ChartLineDefaultDownUp.xlsx"; + using (var p = OpenTemplatePackage(chartName)) + { + var ws = p.Workbook.Worksheets[0]; + var lChart = ws.Drawings[0].As.Chart.LineChart; + + //lChart.Title.Font.Color = Color.DeepSkyBlue; + + lChart.StyleManager.ApplyStyles(); + + SaveAndCleanup(p); + } + + //using(var p= OpenPackage(chartName,false)) + //{ + + //} + } + + ///// + ///// Exports an to a html string + ///// + ///// A html table + //public string GetCssString() + //{ + // using (var ms = EPPlusMemoryManager.GetStream()) + // { + // RenderCss(ms); + // ms.Position = 0; + // using (var sr = new StreamReader(ms)) + // { + // return sr.ReadToEnd(); + // } + // } + //} + ///// + ///// Exports the css part of the html export. + ///// + ///// The stream to write the css to. + ///// + //public void RenderCss(Stream stream) + //{ + // var trueWriter = new CssWriter(stream); + // var cssRules = CreateRuleCollection(_settings); + + // trueWriter.WriteAndClearFlush(cssRules, Settings.Minify); + //} + } +} + diff --git a/src/EPPlus.DrawingRenderer.Tests/TestBase.cs b/src/EPPlus.DrawingRenderer.Tests/TestBase.cs new file mode 100644 index 0000000000..227fafa276 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/TestBase.cs @@ -0,0 +1,570 @@ +/******************************************************************************* + * You may amend and distribute as you like, but don't remove this header! + * + * Required Notice: Copyright (C) EPPlus Software AB. + * https://epplussoftware.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php + * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html + * + * All code and executables are provided "" as is "" with no warranty either express or implied. + * The author accepts no liability for any damage or loss of business that this product may cause. + * + * Code change notes: + * + Date Author Change + ******************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *******************************************************************************/ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml; +using System.IO; +using System.Reflection; +using OfficeOpenXml.Drawing; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; + +[TestClass] +public abstract class TestBase +{ + protected TestBase() + { + } + + private static void GetEnvironment(string key, ref string value, bool isPath) + { + var v = Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.Machine); + if (string.IsNullOrEmpty(v)) + { + v = Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.User); + if (string.IsNullOrEmpty(v)) + { + v = Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.Process); + } + } + if (!string.IsNullOrEmpty(v)) + { + if (isPath && !v.EndsWith("\\")) v += "\\"; + value = v; + } + } + + private class SalesData + { + public string Continent { get; set; } + public string Country { get; set; } + public string State { get; set; } + public double Sales { get; set; } + + } + private class GeoData + { + public string Country { get; set; } + public string State { get; set; } + public double Sales { get; set; } + } + //protected static FileInfo _file; + protected static string _clipartPath = ""; + protected static string _worksheetPath = @"c:\epplusTest\Testoutput\"; + protected static string _testInputPath = AppContext.BaseDirectory + "\\workbooks\\"; + protected static string _testInputPathOptional = @"c:\epplusTest\workbooks\"; //Team shared workbooks for tests + protected static string _testInputLocalPathOptional = @"c:\epplusTest\workbooks\"; //Local workboks for tests + protected static string _imagePath = @"c:\epplusTest\images\"; + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext { get; set; } + static bool _isInitialized = false; + public static void InitBase() + { + _isInitialized = true; + //Gets the paths from environment variables if set. Otherwise uses the default paths as specified in the declaration. + GetEnvironment("EPPlusTestOutputPath", ref _worksheetPath, true); + GetEnvironment("EPPlusTestTemplateLocalPath", ref _testInputLocalPathOptional, true); + GetEnvironment("EPPlusTestTemplateSharedPath", ref _testInputPathOptional, true); + GetEnvironment("EPPlusTestImagePath", ref _imagePath, true); + + + _clipartPath = Path.Combine(Path.GetTempPath(), @"EPPlus clipart"); + if (!Directory.Exists(_clipartPath)) + { + Directory.CreateDirectory(_clipartPath); + } + //if(Environment.GetEnvironmentVariable("EPPlusTestInputPath")!=null) + //{ + // _testInputPathOptional = Environment.GetEnvironmentVariable("EPPlusTestInputPath"); + //} + var asm = Assembly.GetExecutingAssembly(); + var validExtensions = new[] + { + ".gif", ".wmf" + }; + + foreach (var name in asm.GetManifestResourceNames()) + { + foreach (var ext in validExtensions) + { + if (name.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) + { + string fileName = name.Replace("EPPlusTest.Resources.", ""); + using (var stream = asm.GetManifestResourceStream(name)) + using (var file = File.Create(Path.Combine(_clipartPath, fileName))) + { + stream.CopyTo(file); + } + break; + } + } + } + + var di = new DirectoryInfo(_worksheetPath); + _worksheetPath = di.FullName + "\\"; + } + + /// + /// Saves and disposes a package + /// + /// + /// + protected static void SaveAndCleanup(ExcelPackage pck, bool dispose = true) + { + if (pck.Workbook.Worksheets.Count > 0) + { + pck.Save(); + } + if (dispose) pck.Dispose(); + } + protected static void SaveTextFileToWorkbook(string fileName, string content) + { + var file = EnsurePathExists(_worksheetPath + fileName); + File.WriteAllText(file, content); + } + protected void SaveSvg(string fileName, string svg) + { + var file = EnsurePathExists(_imagePath + fileName); + File.WriteAllText(_imagePath + fileName, svg); + } + + + private static string EnsurePathExists(string fileName) + { + var file = new FileInfo(fileName); + if (string.IsNullOrEmpty(file.DirectoryName)==false && Directory.Exists(file.DirectoryName) == false) + { + Directory.CreateDirectory(file.DirectoryName); + } + + return file.FullName; + } + + protected static bool ExistsPackage(string name) + { + var fi = new FileInfo(_worksheetPath + name); + return fi.Exists; + } + protected static void AssertIfNotExists(string name) + { + if (!ExistsPackage(name)) + { + Assert.Inconclusive($"{_worksheetPath}{name} workbook is missing"); + } + } + protected static ExcelPackage OpenPackage(string name, bool delete = false) + { + CreateWorksheetPathIfNotExists(); + var file = new FileInfo(_worksheetPath + name); + if (delete && file.Exists) + { + file.Delete(); + } + return new ExcelPackage(file); + } + protected static async Task OpenPackageAsync(string name, bool delete = false, string password = null) + { + CreateWorksheetPathIfNotExists(); + var file = new FileInfo(_worksheetPath + name); + if (delete && file.Exists) + { + file.Delete(); + } + var p = new ExcelPackage(); + if (password == null) + { + await p.LoadAsync(file).ConfigureAwait(false); + } + else + { + await p.LoadAsync(file, password).ConfigureAwait(false); + } + return p; + } + + static void CreateWorksheetPathIfNotExists() + { + CreatePathIfNotExists(_worksheetPath); + } + protected static void CreatePathIfNotExists(string path) + { + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + protected static ExcelPackage OpenTemplatePackage(string name) + { + var t = new FileInfo(_testInputPath + name); + if (t.Exists) + { + var file = new FileInfo(_worksheetPath + name); + return new ExcelPackage(file, t); + } + else + { + t = new FileInfo(_testInputPathOptional + name); + if (t.Exists) + { + var file = new FileInfo(_worksheetPath + name); + return new ExcelPackage(file, t); + } + t = new FileInfo(_worksheetPath + name); + if (t.Exists) + { + return new ExcelPackage(t); + } + Assert.Inconclusive($"Template {name} does not exist in path {_testInputPath}"); + } + return null; + } + protected static FileInfo GetTemplateFile(string name) + { + var t = new FileInfo(_testInputPath + name); + if (t.Exists) + { + return new FileInfo(_worksheetPath + name); + } + else + { + t = new FileInfo(_testInputPathOptional + name); + if (t.Exists) + { + return t; + } + t = new FileInfo(_worksheetPath + name); + if (t.Exists) + { + return t; + } + + Assert.Inconclusive($"Template File {name} does not exist in path {_testInputPath} or {_worksheetPath}"); + } + return null; + } + protected static FileInfo GetOutputFile(string subPath, string fileName) + { + var path = _worksheetPath + subPath; + if (Directory.Exists(path) == false) + { + Directory.CreateDirectory(path); + } + if (path.EndsWith("\\") == false) path += "\\"; + + return new FileInfo(path + fileName); + } + internal void IsNullRange(ExcelRange address) + { + for (int row = address._fromRow; row <= address._toRow; row++) + { + for (int col = address._fromCol; col <= address._toCol; col++) + { + Assert.IsNull(address._worksheet.Cells[row, col].Value); + } + } + } + protected static void SaveWorkbook(string name, ExcelPackage pck) + { + if (pck.Workbook.Worksheets.Count == 0) return; + var fi = new FileInfo(_worksheetPath + name); + if (fi.Exists) + { + //fi.Delete(); + } + pck.SaveAs(fi); + } + protected static readonly DateTime _loadDataStartDate = new DateTime(2022, 11, 1); + /// + /// Loads 4 columns of {date, numeric, string, numeric} + /// + /// The worksheet + /// Number of items + /// The start column + /// The start row + /// Add a column with hyperlinks + /// Adds a TimeSpan column. Requires add hyperlink to be true + protected static void LoadTestdata(ExcelWorksheet ws, int noItems = 100, int startColumn = 1, int startRow = 1, bool addHyperlinkColumn = false, bool addTimeSpan = false, DateTime? startDate = null) + { + ws.SetValue(1, startColumn, "Date"); + ws.SetValue(1, startColumn + 1, "NumValue"); + ws.SetValue(1, startColumn + 2, "StrValue"); + ws.SetValue(1, startColumn + 3, "NumFormattedValue"); + if (addHyperlinkColumn) + { + ws.SetValue(1, startColumn + 4, "HyperLink"); + } + if (addTimeSpan) + { + ws.SetValue(1, startColumn + 5, "TimeSpan"); + } + + DateTime dt = startDate ?? _loadDataStartDate; + int row = 1; + for (int i = 1; i < noItems; i++) + { + row = startRow + i; + ws.SetValue(row, startColumn, dt); + ws.SetValue(row, startColumn + 1, row); + ws.SetValue(row, startColumn + 2, $"Value {row}"); + ws.SetValue(row, startColumn + 3, row * 33); + if (addHyperlinkColumn) + { + ws.Cells[row, startColumn + 4].SetHyperlink(new Uri("https://epplussoftware.com")); + if (addTimeSpan) + { + ws.SetValue(row, startColumn + 5, new TimeSpan(0, 1, i % 60, 0, 0)); + } + } + + dt = dt.AddDays(1); + } + ws.Cells[startRow, startColumn, row, startColumn].Style.Numberformat.Format = "yyyy-MM-dd"; + if (addTimeSpan) + { + ws.Cells[startRow, startColumn + 5, row, startColumn + 5].Style.Numberformat.Format = "hh:mm:ss"; + } + ws.Cells.AutoFitColumns(); + } + protected static ExcelRangeBase LoadHierarkiTestData(ExcelWorksheet ws) + { + var l = new List + { + new SalesData{ Continent="Europe", Country="Sweden", State = "Stockholm", Sales = 154 }, + new SalesData{ Continent="Asia", Country="Vietnam", State = "Ho Chi Minh", Sales= 88 }, + new SalesData{ Continent="Europe", Country="Sweden", State = "Västerås", Sales = 33 }, + new SalesData{ Continent="Asia", Country="Japan", State = "Tokyo", Sales= 534 }, + new SalesData{ Continent="Europe", Country="Germany", State = "Frankfurt", Sales = 109 }, + new SalesData{ Continent="Asia", Country="Vietnam", State = "Hanoi", Sales= 322 }, + new SalesData{ Continent="Asia", Country="Japan", State = "Osaka", Sales= 88 }, + new SalesData{ Continent="North America", Country="Canada", State = "Vancover", Sales= 99 }, + new SalesData{ Continent="Asia", Country="China", State = "Peking", Sales= 205 }, + new SalesData{ Continent="North America", Country="Canada", State = "Toronto", Sales= 138 }, + new SalesData{ Continent="Europe", Country="France", State = "Lyon", Sales = 185 }, + new SalesData{ Continent="North America", Country="USA", State = "Boston", Sales= 155 }, + new SalesData{ Continent="Europe", Country="France", State = "Paris", Sales = 127 }, + new SalesData{ Continent="North America", Country="USA", State = "New York", Sales= 330 }, + new SalesData{ Continent="Europe", Country="Germany", State = "Berlin", Sales = 210 }, + new SalesData{ Continent="North America", Country="USA", State = "San Fransisco", Sales= 411 }, + }; + + return ws.Cells["A1"].LoadFromCollection(l, true, OfficeOpenXml.Table.TableStyles.Medium12); + } + protected static void LoadGeoTestData(ExcelWorksheet ws) + { + var l = new List + { + new GeoData{ Country="Sweden", State = "Stockholm", Sales = 154 }, + new GeoData{ Country="Sweden", State = "Jämtland", Sales = 55 }, + new GeoData{ Country="Sweden", State = "Västerbotten", Sales = 44}, + new GeoData{ Country="Sweden", State = "Dalarna", Sales = 33 }, + new GeoData{ Country="Sweden", State = "Uppsala", Sales = 22 }, + new GeoData{ Country="Sweden", State = "Skåne", Sales = 47 }, + new GeoData{ Country="Sweden", State = "Halland", Sales = 88 }, + new GeoData{ Country="Sweden", State = "Norrbotten", Sales = 99 }, + new GeoData{ Country="Sweden", State = "Västra Götaland", Sales = 120 }, + new GeoData{ Country="Sweden", State = "Södermanland", Sales = 57 }, + }; + + ws.Cells["A1"].LoadFromCollection(l, true, OfficeOpenXml.Table.TableStyles.Medium12); + } + protected static ExcelRangeBase LoadItemData(ExcelWorksheet ws) + { + ws.Cells["K1"].Value = "Item"; + ws.Cells["L1"].Value = "Category"; + ws.Cells["M1"].Value = "Stock"; + ws.Cells["N1"].Value = "Price"; + ws.Cells["O1"].Value = "Date for grouping"; + + ws.Cells["K2"].Value = "Crowbar"; + ws.Cells["L2"].Value = "Hardware"; + ws.Cells["M2"].Value = 12; + ws.Cells["N2"].Value = 85.2; + ws.Cells["O2"].Value = new DateTime(2010, 1, 31); + + ws.Cells["K3"].Value = "Crowbar"; + ws.Cells["L3"].Value = "Hardware"; + ws.Cells["M3"].Value = 15; + ws.Cells["N3"].Value = 12.2; + ws.Cells["O3"].Value = new DateTime(2010, 2, 28); + + ws.Cells["K4"].Value = "Hammer"; + ws.Cells["L4"].Value = "Hardware"; + ws.Cells["M4"].Value = 550; + ws.Cells["N4"].Value = 72.7; + ws.Cells["O4"].Value = new DateTime(2010, 3, 31); + + ws.Cells["K5"].Value = "Hammer"; + ws.Cells["L5"].Value = "Hardware"; + ws.Cells["M5"].Value = 120; + ws.Cells["N5"].Value = 11.3; + ws.Cells["O5"].Value = new DateTime(2010, 4, 30); + + ws.Cells["K6"].Value = "Crowbar"; + ws.Cells["L6"].Value = "Hardware"; + ws.Cells["M6"].Value = 120; + ws.Cells["N6"].Value = 173.2; + ws.Cells["O6"].Value = new DateTime(2010, 5, 31); + + ws.Cells["K7"].Value = "Hammer"; + ws.Cells["L7"].Value = "Hardware"; + ws.Cells["M7"].Value = 1; + ws.Cells["N7"].Value = 4.2; + ws.Cells["O7"].Value = new DateTime(2010, 6, 30); + + ws.Cells["K8"].Value = "Saw"; + ws.Cells["L8"].Value = "Hardware"; + ws.Cells["M8"].Value = 4; + ws.Cells["N8"].Value = 33.12; + ws.Cells["O8"].Value = new DateTime(2010, 6, 28); + + ws.Cells["K9"].Value = "Screwdriver"; + ws.Cells["L9"].Value = "Hardware"; + ws.Cells["M9"].Value = 1200; + ws.Cells["N9"].Value = 45.2; + ws.Cells["O9"].Value = new DateTime(2010, 8, 31); + + ws.Cells["K10"].Value = "Apple"; + ws.Cells["L10"].Value = "Groceries"; + ws.Cells["M10"].Value = 807; + ws.Cells["N10"].Value = 1.2; + ws.Cells["O10"].Value = new DateTime(2010, 9, 30); + + ws.Cells["K11"].Value = "Butter"; + ws.Cells["L11"].Value = "Groceries"; + ws.Cells["M11"].Value = 52; + ws.Cells["N11"].Value = 7.2; + ws.Cells["O11"].Value = new DateTime(2010, 10, 31); + ws.Cells["O2:O11"].Style.Numberformat.Format = "yyyy-MM-dd"; + return ws.Cells["K1:O11"]; + } + + protected static void SetDateValues(ExcelWorksheet _ws, int noItems = 100) + { + /* Set dates in numeric column */ + _ws.SetValue(50, 2, new DateTime(2018, 12, 15)); + _ws.SetValue(51, 2, new DateTime(2018, 12, 16)); + _ws.SetValue(52, 2, new DateTime(2018, 12, 17)); + _ws.Cells[50, 2, 52, 2].Style.Numberformat.Format = "yyyy-MM-dd"; + + _ws.Cells[1, 1, noItems, 1].Style.Numberformat.Format = "yyyy-MM-dd"; + _ws.Cells[2, 4, noItems, 4].Style.Numberformat.Format = "#,##0.00"; + } + protected int GetRowFromDate(DateTime date, DateTime? initStartDate = null) + { + var startDate = initStartDate ?? _loadDataStartDate; //new DateTime(DateTime.Today.Year-1, 11, 1); + if (startDate > date) + return 2; + else + return (date - startDate).Days + 2; + } + protected static ExcelWorksheet TryGetWorksheet(ExcelPackage pck, string worksheetName) + { + var ws = pck.Workbook.Worksheets[worksheetName]; + if (ws == null) Assert.Inconclusive($"{worksheetName} worksheet is missing"); + return ws; + } + protected static ExcelShape TryGetShape(ExcelPackage pck, string wsName) + { + var ws = pck.Workbook.Worksheets[wsName]; + if (ws == null) Assert.Inconclusive($"{wsName} worksheet is missing"); + var shape = (ExcelShape)ws.Drawings[0]; + return shape; + } + protected static FileInfo GetResourceFile(string fileName) + { + string path = AppContext.BaseDirectory; + while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + { + path = new DirectoryInfo(path + "\\..").FullName; + } + if (path.Length > 4) + { + return new FileInfo(path + "\\Resources\\" + fileName); + } + else + { + return null; + } + } + protected void AssertIsNull(ExcelRangeBase range) + { + foreach (var r in range) + { + Assert.IsNotNull(r.Value); + } + } + protected void AssertNoChange(ExcelRangeBase range) + { + foreach (var r in range) + { + Assert.AreEqual(r.Address, r.Value); + } + } + + protected static void SetValues(ExcelWorksheet ws, int rowcols) + { + for (int r = 1; r <= rowcols; r++) + { + for (int c = 1; c <= rowcols; c++) + { + ws.Cells[r, c].Value = ExcelCellBase.GetAddress(r, c); + } + } + } + protected static MemoryStream GetImageMemoryStream(string imageFile) + { + imageFile = _imagePath + imageFile; + if (File.Exists(imageFile)) + { + return new MemoryStream(File.ReadAllBytes(imageFile)); + } + Assert.Inconclusive($"Image file {imageFile} does not exist"); + return null; + } + CultureInfo _savedCurrentCulture = null; + protected void SwitchToCulture(string cultureCode = "en-US") + { + _savedCurrentCulture = Thread.CurrentThread.CurrentCulture; + Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureCode); + } + protected void SwitchBackToCurrentCulture() + { + if (_savedCurrentCulture == null) + { + throw new InvalidOperationException("Current Culture is not saved. Please use method SwitchToCulture() before using this method."); + } + Thread.CurrentThread.CurrentCulture = _savedCurrentCulture; + + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/TestFontMeasurer.cs b/src/EPPlus.DrawingRenderer.Tests/TestFontMeasurer.cs new file mode 100644 index 0000000000..a92705daff --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/TestFontMeasurer.cs @@ -0,0 +1,361 @@ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System.Drawing; + +namespace TestProject1 +{ + [TestClass] + public class TestFontMeasurer + { + [TestInitialize] + public void Setup() + { + _systemFolderEngine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + } + + [TestCleanup] + public void Cleanup() + { + SystemFolderEngine.Dispose(); + _systemFolderEngine = null; + } + + private OpenTypeFontEngine? _systemFolderEngine; + + private OpenTypeFontEngine SystemFolderEngine => _systemFolderEngine ?? new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + + [TestMethod] + public void CompareFontMeasurer3() + { + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 72.0f, + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + + var testStr = "Hello there⁴₂"; + + var exactWidth = handler.MeasureTextInPixels(testStr); + var exactHeight = handler.GetLineHeightInPoints().PointToPixel(); + + //Ascent+Descent + var lineSpacing = handler.GetLineHeightInPoints().PointToPixel(); + + //Distance between text baseline and top of box AKA Ascent + var getBaseLine = handler.GetAscentInPoints().PointToPixel(); + + var approxHeight = (handler.GetAscentInPoints() - handler.GetDescentInPoints()).PointToPixel(); + + var wholePixelWidth = TextUtils.RoundToWhole(exactWidth); + var wholePixelHeight = TextUtils.RoundToWhole(getBaseLine); + + Assert.AreEqual(90d, wholePixelHeight, 0.1); + } + + [TestMethod] + public void TestWrapText() + { + string fontName = "Aptos Narrow"; + string testStr = "hello the most"; + double fontSize = 11.0d; + double MaxPixelWidth = 54d; + + MeasurementFont mf = new MeasurementFont() + { + FontFamily = fontName, + Size = (float)fontSize, + Style = MeasurementFontStyles.Regular + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + + var strings = handler.WrapText(testStr, MaxPixelWidth.PixelToPoint()); + + Assert.AreEqual("hello the", strings[0]); + Assert.AreEqual("most", strings[1]); + } + + [TestMethod] + public void TestWrapTextLongContinous() + { + string testString = "Hello World! a b c d e f g h i j k l m n o p q r s t u v w x y z \r\n" + + "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Sooooo " + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " + + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCC" + + "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" + + "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" + + "CCCCCCCCCCCCCCCCCCCCCCCCCC"; + double fontSize = 11.0d; + //double MaxPixelWidth = 750d; + double MaxPixelWidth = 750d; + var fontName = "Aptos Narrow"; + MeasurementFont mf = new MeasurementFont() + { + FontFamily = fontName, + Size = (float)fontSize, + Style = MeasurementFontStyles.Regular + }; + var handler = new TextHandler(SystemFolderEngine, mf); + + var strings = handler.WrapText(testString, MaxPixelWidth.PixelToPoint()); + + Assert.AreEqual("Hello World! a b c d e f g h i j k l m n o p q r s t u v w x y z ", strings[0]); + Assert.AreEqual("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Sooooo", strings[1]); + Assert.AreEqual("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", strings[2]); + Assert.AreEqual("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", strings[3]); + Assert.AreEqual("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", strings[4]); + Assert.AreEqual("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCC", strings[5]); + + //Note: We wrap differently from Excel. We assume the kerning is applied correctly which means one extra 'C' fits in these two rows + //And is therefore not part of the last one. + Assert.AreEqual("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", strings[6]); //In excel one less 'C' + Assert.AreEqual("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", strings[7]); //In excel one less 'C' + Assert.AreEqual("CCCCCCCCCCCCCCCCCCCCCCCC", strings[8]);//In excel two more 'C' chars + + + mf.Size = 12f; + + handler.SetFontSize(mf.Size); + + var strings12Size = handler.WrapText(testString, MaxPixelWidth.PixelToPoint()); + Assert.AreEqual("Hello World! a b c d e f g h i j k l m n o p q r s t u v w x y z ", strings12Size[0]); + Assert.AreEqual("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Sooooo", strings12Size[1]); + var actual = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + var render = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + Assert.AreEqual("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", strings12Size[2]); + Assert.AreEqual("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", strings12Size[3]); + + Assert.AreEqual("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", strings12Size[4]); + Assert.AreEqual("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", strings12Size[5]); + Assert.AreEqual("BBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", strings12Size[6]); + Assert.AreEqual("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", strings12Size[7]); + Assert.AreEqual("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", strings12Size[8]); + } + + [TestMethod] + public void SpaceCase2() + { + var text = "fermentum nec rhoncus et, vulputate"; + } + + [TestMethod] + public void SpaceCase() + { + var text = "Praesent ut auctor urna."; + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 11.0f, + }; + var layout = SystemFolderEngine.GetTextLayoutEngineForFont(mf); + var output = layout.WrapText(text, 11f, 39.4); + + var shaper = OpenTypeFonts.GetShaperForFont(mf); + var shapes2 = shaper.ShapeLight("nec rhoncus"); + var width= shapes2.GetWidthInPoints(11f); + //var shaper = OpenTypeFonts.GetShaperForFont(mf); + //var shapes2 = shaper.ShapeLight("ut auctor"); + //var width2 = shapes2.GetWidthInPoints(11f); + + //var width3 = shaper.ShapeLight("ut").GetWidthInPoints(11.0f); + + //Assert.AreEqual(8.84619140625, width3); + Assert.AreEqual("Praesent", output[0]); + Assert.AreEqual("ut auctor", output[1]); + Assert.AreEqual("urna.", output[2]); + } + + [TestMethod] + public void LoremIpsumTesting() + { + var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis"; + + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 11.0f, + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + //float ptMax = 39.68503937007874015748031496063f; + //float ptMax = 36.840393700787401574803149606299f - 1.5f; + //float pixels = 53f; + //float pixels = 46f; + //var ptMax = pixels.PointToPixel(); + + ShapingOptions options = new ShapingOptions(); + + var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + var layout = engine.GetTextLayoutEngineForFont(mf); + + //var wrappedStrings = layout.WrapRichText(new List() { text }, new List() { mf }, 39.4f); + + var shaper = OpenTypeFonts.GetShaperForFont(mf); + + var wrappedStrings = layout.WrapText(text, 11f, 39.4); + + //var shapes1 = shaper.ShapeLight("imperdie"); + //var shapes2 = shaper.ShapeLight("ut auctor"); + //var width = shapes1.GetWidthInPoints(11f); + //var width2 = shapes2.GetWidthInPoints(11f); + var curIndex = 0; + + Assert.AreEqual("Lorem", wrappedStrings[curIndex++]); + Assert.AreEqual("ipsum", wrappedStrings[curIndex++]); + Assert.AreEqual("dolor sit", wrappedStrings[curIndex++]); + Assert.AreEqual("amet,", wrappedStrings[curIndex++]); + Assert.AreEqual("consect", wrappedStrings[curIndex++]); + Assert.AreEqual("etur", wrappedStrings[curIndex++]); + Assert.AreEqual("adipisci", wrappedStrings[curIndex++]); + Assert.AreEqual("ng elit.", wrappedStrings[curIndex++]); + Assert.AreEqual("Nulla", wrappedStrings[curIndex++]); + Assert.AreEqual("pulvinar", wrappedStrings[curIndex++]); + Assert.AreEqual("interdu", wrappedStrings[curIndex++]); + Assert.AreEqual("m", wrappedStrings[curIndex++]); + Assert.AreEqual("imperdie", wrappedStrings[curIndex++]); + Assert.AreEqual("t.", wrappedStrings[curIndex++]); + Assert.AreEqual("Praesent", wrappedStrings[curIndex++]); + Assert.AreEqual("ut auctor", wrappedStrings[curIndex++]); + Assert.AreEqual("urna.", wrappedStrings[curIndex++]); + Assert.AreEqual("Phasellu", wrappedStrings[curIndex++]); + Assert.AreEqual("s", wrappedStrings[curIndex++]); + Assert.AreEqual("sollicitu", wrappedStrings[curIndex++]); + Assert.AreEqual("din", wrappedStrings[curIndex++]); + Assert.AreEqual("quam", wrappedStrings[curIndex++]); + Assert.AreEqual("vitae est", wrappedStrings[curIndex++]); + Assert.AreEqual("convallis", wrappedStrings[curIndex++]); + } + + [TestMethod] + public void WrapDifficultSpotSpace() + { + var text = "facilisis tellus. Morbi "; + var pointWidth = 54.081732283464566929133858267717f; + + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 11.0f, + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + + var wrappedStrings = handler.WrapText(text, pointWidth); + + Assert.AreEqual("facilisis", wrappedStrings[0]); + Assert.AreEqual("tellus.", wrappedStrings[1]);//Difficult part + Assert.AreEqual("Morbi ", wrappedStrings[2]); + } + + [TestMethod] + public void LoremIpsum20Paragraphs() + { + var Lorem20Str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in. Fusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh. Maecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem. Integer congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet. Sed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus. Cras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada. Aliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus. Nullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris. Donec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.Suspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.Cras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.Quisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.Nam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis. Fusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci. Vivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida. In in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum. Donec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo. Donec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum. Nunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; + + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 11.0f, + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + + double maxPixelWidth = 72d; + + var wrappedStrings = handler.WrapText(Lorem20Str, maxPixelWidth.PixelToPoint()); + + const string SavedComparisonString = "Lorem\r\nipsum dolor\r\nsit amet,\r\nconsectetur\r\nadipiscing\r\nelit. Nulla\r\npulvinar\r\ninterdum\r\nimperdiet.\r\nPraesent ut\r\nauctor urna.\r\nPhasellus\r\nsollicitudin\r\nquam vitae\r\nest\r\nconvallis,\r\neu mattis\r\nlorem\r\nefficitur.\r\nMauris nulla\r\nlibero,\r\ntincidunt id\r\nipsum non,\r\nlobortis\r\ntristique\r\nmauris.\r\nDonec ut\r\nenim sed\r\nenim\r\nfermentum\r\nmolestie vel\r\nquis odio.\r\nMorbi a\r\nfermentum\r\nmassa, sit\r\namet\r\nultrices est.\r\nAenean\r\nante mi,\r\nfermentum\r\nnec\r\nrhoncus et,\r\nvulputate\r\nvel sapien.\r\nDonec\r\ntempus, leo\r\nquis luctus\r\nrhoncus,\r\naugue odio\r\npharetra\r\nlibero, ac\r\nblandit urna\r\nturpis sed\r\ndiam.\r\nVivamus\r\naugue\r\npurus,\r\neleifend et\r\njusto\r\nfacilisis,\r\nimperdiet\r\nrhoncus\r\nsem.\r\nQuisque\r\naccumsan\r\npellentesqu\r\ne elit, eget\r\nfinibus\r\nmassa\r\naccumsan\r\nin. Fusce eu\r\naccumsan\r\nenim. Cras\r\npulvinar\r\nenim vel\r\ntellus\r\nlacinia,\r\nconsectetur\r\neuismod\r\ntortor\r\nconsectetur\r\n. Praesent\r\ntincidunt\r\npretium\r\neros, ac\r\nauctor\r\nmagna\r\nluctus sed.\r\nUt porta\r\nlectus\r\nquam, non\r\nornare\r\nmauris\r\nlacinia sit\r\namet.\r\nNullam\r\negestas\r\ndolor quis\r\nmagna\r\nporttitor, ac\r\niaculis nisi\r\nhendrerit.\r\nProin at\r\nmollis\r\nlacus, in\r\nporttitor\r\nnunc.\r\nAliquam\r\nerat\r\nvolutpat.\r\nSed vel\r\negestas\r\nrisus, at\r\naliquam\r\narcu.\r\nVestibulum\r\nquis\r\nlobortis\r\nnulla. Etiam\r\npellentesqu\r\ne auctor\r\nnulla, eget\r\ntincidunt\r\nfelis\r\nrhoncus id.\r\nSed metus\r\nante,\r\nefficitur id\r\ndui eu,\r\nfermentum\r\nmollis odio.\r\nPhasellus\r\nullamcorper\r\niaculis\r\naugue vel\r\nconsequat.\r\nEtiam\r\nfringilla\r\neuismod\r\ninterdum.\r\nUt molestie\r\nmassa id\r\nfringilla\r\nlobortis.\r\nVestibulum\r\nmalesuada,\r\nante vel\r\nmattis\r\nultrices,\r\nsem ante\r\nmolestie\r\naugue, non\r\ntristique dui\r\nmi non\r\nnibh.\r\nMaecenas\r\ndictum,\r\nsem eget\r\nconvallis\r\nrhoncus,\r\nlacus enim\r\nporta\r\nneque, in\r\nposuere dui\r\nex a sapien.\r\nNam lacus\r\nnibh,\r\nposuere sed\r\nelit eget,\r\ncondimentu\r\nm facilisis\r\nligula. Cras\r\nconsectetur\r\nlacus\r\nullamcorper\r\nvelit aliquet\r\nbibendum\r\neget vel\r\nnulla.\r\nAenean\r\nvarius ac\r\nerat quis\r\nullamcorper\r\n. Donec\r\nlaoreet arcu\r\na lorem\r\nvolutpat\r\nfaucibus.\r\nVivamus\r\nvehicula leo\r\nut erat\r\nluctus\r\nscelerisque.\r\nMorbi\r\nposuere ex\r\net magna\r\negestas\r\nfacilisis.\r\nFusce\r\nscelerisque\r\nvolutpat\r\nerat\r\nbibendum\r\nhendrerit.\r\nNam blandit\r\nmi ut metus\r\npulvinar, vel\r\ntempus\r\nlacus\r\neuismod.\r\nQuisque\r\nimperdiet\r\nsit amet\r\nsapien sed\r\nultricies.\r\nPhasellus\r\nsodales,\r\nipsum vitae\r\ntincidunt\r\nfacilisis,\r\nnulla ligula\r\nfaucibus\r\nfelis, eget\r\nvehicula\r\nante lacus\r\neu lorem.\r\nInteger\r\ncongue\r\ndiam ac\r\nviverra\r\ntristique.\r\nCurabitur\r\ntristique\r\ndolor quis\r\nquam\r\npretium, et\r\nscelerisque\r\nquam\r\ndictum.\r\nMaecenas\r\nvitae\r\nsodales\r\nligula.\r\nPellentesqu\r\ne maximus\r\ndiam vel\r\nporta\r\nconvallis. Ut\r\naliquam\r\neros quis\r\nporta\r\npellentesqu\r\ne. Fusce in\r\nex ut mi\r\negestas\r\ncursus.\r\nAliquam\r\nerat\r\nvolutpat.\r\nCras laoreet\r\ncondimentu\r\nm laoreet.\r\nSed eget\r\nfacilisis\r\ntellus.\r\nMorbi\r\nviverra odio\r\nsed odio\r\nplacerat\r\nmollis. Duis\r\nturpis\r\nmetus,\r\ndignissim\r\nvarius urna\r\nquis, viverra\r\ndignissim\r\ndui.\r\nVivamus\r\nviverra at\r\nnisi quis\r\nconvallis.\r\nSuspendiss\r\ne fringilla\r\nrisus et ante\r\nsollicitudin,\r\nsed eleifend\r\nsem\r\nplacerat.\r\nProin\r\npretium\r\nblandit\r\narcu, eget\r\nrhoncus\r\nrisus\r\nhendrerit at.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nPhasellus\r\nvulputate\r\nefficitur\r\nmaximus.\r\nCras blandit\r\nnulla eu nisi\r\nauctor\r\ntempus.\r\nSed pretium\r\nlacus ac\r\nmagna\r\nvestibulum,\r\naliquam\r\nfaucibus\r\norci luctus.\r\nMauris enim\r\nlorem,\r\nvarius ut\r\nante quis,\r\nvarius\r\nviverra\r\nlectus.\r\nFusce\r\nblandit nibh\r\nvel feugiat\r\nefficitur.\r\nDonec\r\nmaximus id\r\njusto ac\r\nmollis.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nplacerat\r\nlectus et\r\npurus\r\ndictum, id\r\ncongue nisi\r\neuismod.\r\nMaecenas\r\neuismod\r\nfermentum\r\ndiam, sit\r\namet\r\ngravida\r\nmagna\r\nsuscipit a.\r\nQuisque\r\nconsectetur\r\narcu eu\r\nnunc\r\nsodales\r\nscelerisque.\r\nNulla non\r\ntincidunt\r\nnulla.\r\nPellentesqu\r\ne ut tortor\r\nvel enim\r\nconvallis\r\nmalesuada.\r\nAliquam\r\nultricies\r\nbibendum\r\nultrices.\r\nMauris\r\nrutrum ac\r\nnisl vel\r\nluctus.\r\nDonec quis\r\nnibh vitae\r\norci ultricies\r\ngravida.\r\nAliquam\r\nvitae velit\r\nporttitor\r\nlorem\r\nbibendum\r\nfringilla\r\nvolutpat a\r\neros.\r\nCurabitur at\r\ncommodo\r\ntortor. Etiam\r\nultricies,\r\nneque et\r\niaculis\r\neuismod,\r\ndiam ligula\r\nluctus mi,\r\nvitae\r\nlobortis felis\r\nlorem eu\r\nnulla. Sed a\r\nsemper ex.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNulla\r\nmauris elit,\r\npulvinar ac\r\ntortor et,\r\nluctus\r\nhendrerit\r\nnisl. In\r\negestas\r\nauctor urna\r\nvitae\r\nlaoreet.\r\nPraesent\r\nbibendum\r\negestas\r\nconvallis.\r\nProin non\r\nsuscipit\r\ntellus.\r\nNullam at\r\nnibh in urna\r\nlaoreet\r\nsodales non\r\nvel tellus.\r\nDonec in\r\nenim dui.\r\nPhasellus\r\nquis quam\r\ntincidunt,\r\npellentesqu\r\ne lorem ac,\r\nscelerisque\r\nneque.\r\nInteger nec\r\ntempus\r\nurna. Donec\r\nelit massa,\r\neleifend eu\r\nsapien sit\r\namet,\r\nmollis\r\npellentesqu\r\ne est.\r\nNullam\r\ntristique\r\ntellus\r\niaculis arcu\r\nconsectetur\r\npretium.\r\nSed\r\nvenenatis\r\nconvallis\r\nscelerisque.\r\nSuspendiss\r\ne varius\r\nurna sit\r\namet purus\r\naccumsan,\r\nid ultricies\r\nerat\r\nefficitur.\r\nCras non\r\nipsum eget\r\nnulla\r\nefficitur\r\ncommodo\r\nsit amet non\r\nlacus. Proin\r\nviverra enim\r\nsit amet\r\nenim\r\ntempus\r\nullamcorper\r\n. Class\r\naptent taciti\r\nsociosqu ad\r\nlitora\r\ntorquent per\r\nconubia\r\nnostra, per\r\ninceptos\r\nhimenaeos.\r\nDuis ac\r\nmassa\r\ninterdum,\r\ngravida ex\r\negestas,\r\nfinibus\r\npurus. Nunc\r\nconsectetur\r\ncommodo\r\nlacus, ac\r\nconvallis\r\nquam\r\nlobortis eu.\r\nSed\r\nconvallis\r\ntempor\r\ncommodo.\r\nNulla sed\r\nconvallis\r\nmauris.\r\nDonec\r\nvenenatis\r\nnisi est, ac\r\nullamcorper\r\nmi pretium\r\nquis. Donec\r\nvitae eros at\r\nipsum\r\ninterdum\r\nscelerisque\r\nnec vitae\r\nnisi. Sed\r\nvestibulum\r\nerat ac\r\nbibendum\r\ndapibus.\r\nMorbi nec\r\nelit id quam\r\ntristique\r\ncursus id\r\nsed sem.\r\nPraesent\r\nnon ante\r\nenim.\r\nPellentesqu\r\ne habitant\r\nmorbi\r\ntristique\r\nsenectus et\r\nnetus et\r\nmalesuada\r\nfames ac\r\nturpis\r\negestas.\r\nPraesent\r\nnon mauris\r\ndui.\r\nAliquam\r\nrhoncus\r\nmattis ante\r\nsed\r\nvenenatis.\r\nVivamus\r\nvehicula\r\nsed sapien\r\nsed dictum.\r\nIn aliquet,\r\nurna\r\nefficitur\r\ntincidunt\r\nlobortis,\r\nnibh justo\r\ntristique\r\npurus, sed\r\nvolutpat\r\nrisus magna\r\net\r\nlibero.Susp\r\nendisse\r\nlectus justo,\r\nvarius eget\r\narcu et,\r\nsemper\r\nlaoreet erat.\r\nQuisque\r\neget lacus\r\nornare,\r\npellentesqu\r\ne erat sit\r\namet,\r\nvulputate\r\nfelis. Duis\r\nluctus,\r\nmassa a\r\npellentesqu\r\ne mollis,\r\nmassa elit\r\nconvallis\r\nmi, vel\r\nbibendum\r\nex ex eu\r\npurus.\r\nSuspendiss\r\ne vel\r\nfermentum\r\nurna, ac\r\ncommodo\r\nenim.\r\nMauris\r\ntincidunt\r\ncursus elit,\r\na volutpat\r\nlibero\r\ncommodo\r\net. Etiam\r\ndapibus\r\nlibero\r\nvenenatis\r\ntellus\r\nlobortis, vel\r\nlacinia elit\r\nfaucibus.\r\nMaecenas\r\nsemper sed\r\nquam quis\r\nfinibus.\r\nInteger\r\nefficitur,\r\nlibero\r\nimperdiet\r\nsollicitudin\r\ncommodo,\r\nelit arcu\r\nvulputate\r\nest, eget\r\nfinibus mi\r\nurna sit\r\namet\r\nmagna.\r\nCras\r\nullamcorper\r\nconsequat\r\nornare.\r\nFusce\r\nconvallis\r\nnunc vel\r\nrisus\r\ncursus, at\r\nmaximus\r\nligula\r\ncursus.\r\nPellentesqu\r\ne vulputate\r\nrisus libero,\r\neget cursus\r\nnibh\r\nsodales\r\nsed. Donec\r\naccumsan\r\nsem et\r\nmassa\r\nsemper, id\r\ndignissim\r\nvelit\r\nvehicula.Cr\r\nas cursus\r\nipsum ac\r\nerat\r\nvehicula,\r\nnec iaculis\r\npurus\r\ndictum.\r\nQuisque\r\nlacinia elit\r\nvitae leo\r\ndictum, vel\r\ndignissim\r\nvelit\r\ndapibus.\r\nAenean sem\r\nnisi,\r\nfaucibus\r\ninterdum\r\njusto eu,\r\neuismod\r\nporttitor ex.\r\nMorbi et\r\nlectus\r\nlectus. Duis\r\nneque felis,\r\nsuscipit at\r\nscelerisque\r\neu,\r\nscelerisque\r\nid orci.\r\nCurabitur et\r\nplacerat\r\nipsum.\r\nProin\r\ngravida\r\nsapien nisl,\r\net varius\r\nipsum\r\nmollis nec.\r\nQuisque\r\ndignissim\r\nconsectetur\r\nfeugiat.\r\nAenean\r\neros purus,\r\nlaoreet\r\ninterdum\r\nrutrum at,\r\naliquet sit\r\namet\r\nlectus.\r\nDonec\r\ngravida\r\nlorem ut\r\ntincidunt\r\nlaoreet.\r\nDonec\r\nconsequat\r\nviverra\r\nligula, in\r\naccumsan\r\nmi\r\nbibendum\r\nscelerisque.\r\nQuisque ac\r\nrisus justo.\r\nMorbi\r\nmagna\r\narcu,\r\negestas nec\r\nluctus\r\ncommodo,\r\ncursus eget\r\nnunc.\r\nVivamus\r\neuismod\r\nlorem ex, et\r\nmaximus\r\nfelis\r\nhendrerit\r\neget.\r\nNullam\r\nullamcorper\r\neuismod\r\nligula, et\r\niaculis\r\nligula\r\nultricies a.\r\nFusce\r\naliquam,\r\nenim vel\r\nfermentum\r\nultrices, elit\r\nquam\r\nsemper\r\nerat, vitae\r\nsemper velit\r\naugue non\r\nmagna.Quis\r\nque\r\nmaximus\r\nsemper\r\narcu, id\r\npellentesqu\r\ne est\r\ntempus a.\r\nPhasellus\r\nlacus elit,\r\nauctor sit\r\namet lacinia\r\na, dapibus\r\nvitae velit.\r\nPhasellus ut\r\npharetra\r\njusto, ut\r\nultricies\r\nerat. Sed\r\nmolestie\r\nsapien vel\r\ninterdum\r\nlobortis.\r\nNulla\r\nfacilisi.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nnec mauris\r\nquis nisi\r\nvulputate\r\ngravida quis\r\nnec\r\nvelit.Nam et\r\ncongue\r\nipsum.\r\nNulla vel elit\r\nnon dolor\r\nmollis\r\naliquet vel\r\nat magna.\r\nPellentesqu\r\ne nec\r\nfacilisis elit.\r\nIn vulputate\r\nquis sem\r\nporta\r\nsuscipit.\r\nNullam sed\r\nex ornare\r\nnibh\r\nsuscipit\r\nmattis quis\r\nnon lacus.\r\nMauris vel\r\nex urna.\r\nVivamus\r\nultricies\r\nsapien sit\r\namet sapien\r\nvehicula\r\ngravida.\r\nDonec\r\nfeugiat\r\nvolutpat\r\nquam.\r\nVestibulum\r\nauctor\r\ndictum nisl,\r\nid hendrerit\r\nmetus\r\nullamcorper\r\nsed. Nulla\r\nmaximus\r\nlacus vel\r\nmollis\r\nmaximus.\r\nNulla\r\nlaoreet\r\nplacerat\r\nquam eu\r\nviverra.\r\nEtiam\r\nfeugiat\r\naccumsan\r\nnisl a\r\ncondimentu\r\nm. Sed\r\nultricies\r\nante ante,\r\nac auctor\r\nligula\r\ngravida nec.\r\nPraesent a\r\nneque\r\ndignissim,\r\nsagittis felis\r\nsit amet,\r\ncondimentu\r\nm turpis.\r\nFusce at leo\r\nvel est\r\nblandit\r\nmalesuada.\r\nPellentesqu\r\ne et neque\r\nnon metus\r\npellentesqu\r\ne imperdiet.\r\nPraesent\r\npellentesqu\r\ne lacinia\r\nlorem, et\r\ntristique\r\ntellus\r\nefficitur id.\r\nSuspendiss\r\ne aliquet\r\nultricies\r\njusto vitae\r\ninterdum.\r\nCras\r\ntristique\r\nviverra\r\nquam, eget\r\ngravida mi\r\nfermentum\r\nimperdiet.\r\nSed\r\nimperdiet\r\nvitae purus\r\nut volutpat.\r\nNulla\r\nlacinia elit\r\nin\r\nfermentum\r\nconsectetur\r\n. Phasellus\r\ncommodo\r\nut nisl sit\r\namet\r\nsagittis.\r\nDuis ac\r\nornare orci.\r\nVivamus vel\r\nenim\r\nposuere,\r\npharetra ex\r\nvel,\r\nelementum\r\nest.\r\nVestibulum\r\ncommodo\r\nluctus\r\nmetus eget\r\nmaximus.\r\nSuspendiss\r\ne a nulla a\r\nodio\r\neleifend\r\nfaucibus.\r\nSuspendiss\r\ne semper\r\nlacus non\r\nporttitor\r\naliquet.\r\nCras ac\r\nscelerisque\r\nmagna, et\r\npulvinar\r\njusto.\r\nInteger\r\ncursus\r\npulvinar\r\nfringilla.\r\nMauris\r\nimperdiet\r\nnibh sit\r\namet\r\ntempor\r\nlaoreet.\r\nMorbi\r\ntincidunt\r\ntortor ex, sit\r\namet\r\nmaximus\r\npurus\r\ntristique\r\nquis.\r\nQuisque\r\nsed\r\nhendrerit\r\nvelit. Mauris\r\nmattis nibh\r\nut eros\r\nluctus, eget\r\nmattis\r\nmassa\r\nauctor.\r\nPhasellus\r\neu neque at\r\naugue\r\ngravida\r\nsagittis nec\r\nnon tortor.\r\nEtiam\r\nporttitor\r\nsem\r\nsodales mi\r\nullamcorper\r\ngravida. In\r\nin dictum\r\norci. In vitae\r\nvestibulum\r\nquam. Cras\r\naugue eros,\r\ntincidunt ac\r\nelit posuere,\r\nsollicitudin\r\nefficitur\r\nlectus.\r\nPraesent\r\nquis\r\nsodales\r\nnisl. Proin\r\nsit amet\r\nmolestie\r\nest. In\r\ncommodo\r\nmauris vel\r\nmauris\r\nefficitur,\r\nnec mollis\r\nmauris\r\nsagittis.\r\nCras ligula\r\nnibh,\r\negestas sit\r\namet eros\r\nin, lacinia\r\ntristique\r\nmagna.\r\nCras risus\r\nlibero,\r\nlacinia eget\r\nlibero vitae,\r\nmaximus\r\naliquet\r\nnibh. Mauris\r\nid sodales\r\npurus, vitae\r\ndictum\r\nlectus. Cras\r\nconsectetur\r\nligula velit,\r\ntempus\r\npulvinar\r\nlacus\r\nporttitor\r\nvitae.\r\nPhasellus\r\neget tellus\r\nipsum.\r\nDonec\r\ninterdum\r\nlaoreet elit\r\nnon\r\nvestibulum.\r\nCras sed\r\nurna\r\nullamcorper\r\n, aliquam\r\nerat eget,\r\nporta orci.\r\nVestibulum\r\neget congue\r\nnulla. Sed\r\nsem tortor,\r\neuismod at\r\nrutrum id,\r\nsagittis a\r\nnunc. Duis\r\nin nibh\r\nfacilisis,\r\ndignissim\r\npurus ut,\r\nhendrerit\r\nmagna. Sed\r\nsemper\r\nligula id\r\nmassa\r\nelementum,\r\nnon\r\nmalesuada\r\nvelit\r\negestas.\r\nNullam\r\ndictum, mi\r\nnec\r\neuismod\r\nsagittis,\r\nligula leo\r\nullamcorper\r\ndolor, quis\r\nfaucibus\r\nodio metus\r\neget magna.\r\nUt gravida\r\nmetus non\r\nmetus\r\nbibendum\r\nbibendum.\r\nIn sagittis\r\neleifend\r\naliquet.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNam mollis\r\nsagittis\r\nfelis, in\r\nfaucibus\r\ntortor\r\npretium vel.\r\nNam nec\r\nenim\r\nmetus.\r\nDonec in\r\naugue arcu.\r\nProin non\r\nlobortis\r\npurus, sit\r\namet lacinia\r\nelit.\r\nSuspendiss\r\ne quis eros\r\ncondimentu\r\nm, blandit\r\njusto sit\r\namet,\r\nlobortis nisl.\r\nSuspendiss\r\ne maximus\r\nmassa sed\r\nurna tempor\r\nornare.\r\nNunc\r\nmalesuada\r\npurus odio,\r\neu luctus\r\nlectus\r\nauctor nec.\r\nMorbi\r\nauctor\r\npellentesqu\r\ne auctor.\r\nSed\r\nullamcorper\r\n, ex vitae\r\naliquam\r\nvulputate,\r\nest diam\r\nfeugiat mi,\r\nid porttitor\r\nlectus orci\r\nac leo.\r\nDonec sit\r\namet velit\r\npulvinar,\r\nvenenatis\r\nturpis ut,\r\ninterdum\r\nligula.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nVestibulum\r\neu lacus\r\nurna.\r\nMaecenas\r\nsem nulla,\r\naccumsan\r\neu ultricies\r\nsed, tempor\r\nvel magna.\r\nCras aliquet\r\nsollicitudin\r\nsapien ac\r\npulvinar.\r\nPraesent ac\r\nsodales mi.\r\nInteger vitae\r\nmauris\r\nmassa.\r\nMaecenas\r\niaculis orci\r\net faucibus\r\ninterdum.\r\nNunc nec\r\nmaximus\r\nfelis, sed\r\nfinibus\r\nquam.\r\nPellentesqu\r\ne felis\r\nmassa,\r\nvestibulum\r\nin tellus\r\nvitae,\r\ncongue\r\ntincidunt\r\njusto. Nunc\r\nvitae enim\r\nmalesuada,\r\nbibendum\r\nante nec,\r\nvarius\r\ntellus.\r\nPraesent\r\nvitae nisi id\r\nquam\r\nauctor\r\nlacinia at\r\nnon quam.\r\nNam nec\r\nligula sit\r\namet felis\r\nauctor\r\nsagittis.\r\nNunc in\r\nrisus eu\r\nurna varius\r\nlaoreet quis\r\nsit amet\r\nfelis. Morbi\r\nvarius\r\ntempor orci,\r\neu\r\nvestibulum\r\nnunc\r\nvestibulum\r\nac. Nunc\r\nvehicula\r\nvelit\r\neleifend\r\nconsequat\r\nporta.\r\nSuspendiss\r\ne maximus\r\ndapibus\r\norci, in\r\nvulputate\r\nmassa\r\npretium ac.\r\nQuisque\r\nmalesuada\r\naliquet\r\naliquet."; + + var savedStrings = SavedComparisonString.Split(new string[] { "\r\n" }, StringSplitOptions.None); + + List faultyStrings = new(); + List excpectedStrings = new(); + List indiciesOfDifferingString = new(); + + for (int i = 0; i < savedStrings.Count(); i++) + { + if(savedStrings[i] != wrappedStrings[i]) + { + indiciesOfDifferingString.Add(i); + faultyStrings.Add(wrappedStrings[i]); + excpectedStrings.Add(savedStrings[i]); + } + } + + if(indiciesOfDifferingString.Count != 0) + { + //The start of indicies diverging + Assert.IsNull(indiciesOfDifferingString[0]); + Assert.AreEqual(faultyStrings[0], excpectedStrings[0]); + } + + Assert.AreEqual(0, faultyStrings.Count); + } + + [TestMethod] + public void LoremIpsum20ParagraphsMultipleFragments() + { + var Lorem20Str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in. Fusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh. Maecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem. Integer congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet. Sed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus. Cras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada. Aliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus. Nullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris. Donec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.Suspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.Cras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.Quisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.Nam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis. Fusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci. Vivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida. In in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum. Donec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo. Donec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum. Nunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; + const string SavedComparisonString = "Lorem\r\nipsum dolor\r\nsit amet,\r\nconsectetur\r\nadipiscing\r\nelit. Nulla\r\npulvinar\r\ninterdum\r\nimperdiet.\r\nPraesent ut\r\nauctor urna.\r\nPhasellus\r\nsollicitudin\r\nquam vitae\r\nest\r\nconvallis,\r\neu mattis\r\nlorem\r\nefficitur.\r\nMauris nulla\r\nlibero,\r\ntincidunt id\r\nipsum non,\r\nlobortis\r\ntristique\r\nmauris.\r\nDonec ut\r\nenim sed\r\nenim\r\nfermentum\r\nmolestie vel\r\nquis odio.\r\nMorbi a\r\nfermentum\r\nmassa, sit\r\namet\r\nultrices est.\r\nAenean\r\nante mi,\r\nfermentum\r\nnec rhoncus\r\net,\r\nvulputate\r\nvel sapien.\r\nDonec\r\ntempus, leo\r\nquis luctus\r\nrhoncus,\r\naugue odio\r\npharetra\r\nlibero, ac\r\nblandit urna\r\nturpis sed\r\ndiam.\r\nVivamus\r\naugue\r\npurus,\r\neleifend et\r\njusto\r\nfacilisis,\r\nimperdiet\r\nrhoncus\r\nsem.\r\nQuisque\r\naccumsan\r\npellentesqu\r\ne elit, eget\r\nfinibus\r\nmassa\r\naccumsan\r\nin. Fusce eu\r\naccumsan\r\nenim. Cras\r\npulvinar\r\nenim vel\r\ntellus\r\nlacinia,\r\nconsectetur\r\neuismod\r\ntortor\r\nconsectetur\r\n. Praesent\r\ntincidunt\r\npretium\r\neros, ac\r\nauctor\r\nmagna\r\nluctus sed.\r\nUt porta\r\nlectus\r\nquam, non\r\nornare\r\nmauris\r\nlacinia sit\r\namet.\r\nNullam\r\negestas\r\ndolor quis\r\nmagna\r\nporttitor, ac\r\niaculis nisi\r\nhendrerit.\r\nProin at\r\nmollis\r\nlacus, in\r\nporttitor\r\nnunc.\r\nAliquam\r\nerat\r\nvolutpat.\r\nSed vel\r\negestas\r\nrisus, at\r\naliquam\r\narcu.\r\nVestibulum\r\nquis\r\nlobortis\r\nnulla. Etiam\r\npellentesqu\r\ne auctor\r\nnulla, eget\r\ntincidunt\r\nfelis\r\nrhoncus id.\r\nSed metus\r\nante,\r\nefficitur id\r\ndui eu,\r\nfermentum\r\nmollis odio.\r\nPhasellus\r\nullamcorper\r\niaculis\r\naugue vel\r\nconsequat.\r\nEtiam\r\nfringilla\r\neuismod\r\ninterdum.\r\nUt molestie\r\nmassa id\r\nfringilla\r\nlobortis.\r\nVestibulum\r\nmalesuada,\r\nante vel\r\nmattis\r\nultrices,\r\nsem ante\r\nmolestie\r\naugue, non\r\ntristique dui\r\nmi non nibh.\r\nMaecenas\r\ndictum,\r\nsem eget\r\nconvallis\r\nrhoncus,\r\nlacus enim\r\nporta\r\nneque, in\r\nposuere dui\r\nex a sapien.\r\nNam lacus\r\nnibh,\r\nposuere sed\r\nelit eget,\r\ncondimentu\r\nm facilisis\r\nligula. Cras\r\nconsectetur\r\nlacus\r\nullamcorper\r\nvelit aliquet\r\nbibendum\r\neget vel\r\nnulla.\r\nAenean\r\nvarius ac\r\nerat quis\r\nullamcorper\r\n. Donec\r\nlaoreet arcu\r\na lorem\r\nvolutpat\r\nfaucibus.\r\nVivamus\r\nvehicula leo\r\nut erat\r\nluctus\r\nscelerisque.\r\nMorbi\r\nposuere ex\r\net magna\r\negestas\r\nfacilisis.\r\nFusce\r\nscelerisque\r\nvolutpat\r\nerat\r\nbibendum\r\nhendrerit.\r\nNam blandit\r\nmi ut metus\r\npulvinar, vel\r\ntempus\r\nlacus\r\neuismod.\r\nQuisque\r\nimperdiet\r\nsit amet\r\nsapien sed\r\nultricies.\r\nPhasellus\r\nsodales,\r\nipsum vitae\r\ntincidunt\r\nfacilisis,\r\nnulla ligula\r\nfaucibus\r\nfelis, eget\r\nvehicula\r\nante lacus\r\neu lorem.\r\nInteger\r\ncongue\r\ndiam ac\r\nviverra\r\ntristique.\r\nCurabitur\r\ntristique\r\ndolor quis\r\nquam\r\npretium, et\r\nscelerisque\r\nquam\r\ndictum.\r\nMaecenas\r\nvitae\r\nsodales\r\nligula.\r\nPellentesqu\r\ne maximus\r\ndiam vel\r\nporta\r\nconvallis. Ut\r\naliquam\r\neros quis\r\nporta\r\npellentesqu\r\ne. Fusce in\r\nex ut mi\r\negestas\r\ncursus.\r\nAliquam\r\nerat\r\nvolutpat.\r\nCras laoreet\r\ncondimentu\r\nm laoreet.\r\nSed eget\r\nfacilisis\r\ntellus.\r\nMorbi\r\nviverra odio\r\nsed odio\r\nplacerat\r\nmollis. Duis\r\nturpis\r\nmetus,\r\ndignissim\r\nvarius urna\r\nquis, viverra\r\ndignissim\r\ndui.\r\nVivamus\r\nviverra at\r\nnisi quis\r\nconvallis.\r\nSuspendiss\r\ne fringilla\r\nrisus et ante\r\nsollicitudin,\r\nsed eleifend\r\nsem\r\nplacerat.\r\nProin\r\npretium\r\nblandit\r\narcu, eget\r\nrhoncus\r\nrisus\r\nhendrerit at.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nPhasellus\r\nvulputate\r\nefficitur\r\nmaximus.\r\nCras blandit\r\nnulla eu nisi\r\nauctor\r\ntempus.\r\nSed pretium\r\nlacus ac\r\nmagna\r\nvestibulum,\r\naliquam\r\nfaucibus\r\norci luctus.\r\nMauris enim\r\nlorem,\r\nvarius ut\r\nante quis,\r\nvarius\r\nviverra\r\nlectus.\r\nFusce\r\nblandit nibh\r\nvel feugiat\r\nefficitur.\r\nDonec\r\nmaximus id\r\njusto ac\r\nmollis.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nplacerat\r\nlectus et\r\npurus\r\ndictum, id\r\ncongue nisi\r\neuismod.\r\nMaecenas\r\neuismod\r\nfermentum\r\ndiam, sit\r\namet\r\ngravida\r\nmagna\r\nsuscipit a.\r\nQuisque\r\nconsectetur\r\narcu eu\r\nnunc\r\nsodales\r\nscelerisque.\r\nNulla non\r\ntincidunt\r\nnulla.\r\nPellentesqu\r\ne ut tortor\r\nvel enim\r\nconvallis\r\nmalesuada.\r\nAliquam\r\nultricies\r\nbibendum\r\nultrices.\r\nMauris\r\nrutrum ac\r\nnisl vel\r\nluctus.\r\nDonec quis\r\nnibh vitae\r\norci ultricies\r\ngravida.\r\nAliquam\r\nvitae velit\r\nporttitor\r\nlorem\r\nbibendum\r\nfringilla\r\nvolutpat a\r\neros.\r\nCurabitur at\r\ncommodo\r\ntortor. Etiam\r\nultricies,\r\nneque et\r\niaculis\r\neuismod,\r\ndiam ligula\r\nluctus mi,\r\nvitae\r\nlobortis felis\r\nlorem eu\r\nnulla. Sed a\r\nsemper ex.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNulla\r\nmauris elit,\r\npulvinar ac\r\ntortor et,\r\nluctus\r\nhendrerit\r\nnisl. In\r\negestas\r\nauctor urna\r\nvitae\r\nlaoreet.\r\nPraesent\r\nbibendum\r\negestas\r\nconvallis.\r\nProin non\r\nsuscipit\r\ntellus.\r\nNullam at\r\nnibh in urna\r\nlaoreet\r\nsodales non\r\nvel tellus.\r\nDonec in\r\nenim dui.\r\nPhasellus\r\nquis quam\r\ntincidunt,\r\npellentesqu\r\ne lorem ac,\r\nscelerisque\r\nneque.\r\nInteger nec\r\ntempus\r\nurna. Donec\r\nelit massa,\r\neleifend eu\r\nsapien sit\r\namet,\r\nmollis\r\npellentesqu\r\ne est.\r\nNullam\r\ntristique\r\ntellus\r\niaculis arcu\r\nconsectetur\r\npretium.\r\nSed\r\nvenenatis\r\nconvallis\r\nscelerisque.\r\nSuspendiss\r\ne varius\r\nurna sit\r\namet purus\r\naccumsan,\r\nid ultricies\r\nerat\r\nefficitur.\r\nCras non\r\nipsum eget\r\nnulla\r\nefficitur\r\ncommodo\r\nsit amet non\r\nlacus. Proin\r\nviverra enim\r\nsit amet\r\nenim\r\ntempus\r\nullamcorper\r\n. Class\r\naptent taciti\r\nsociosqu ad\r\nlitora\r\ntorquent per\r\nconubia\r\nnostra, per\r\ninceptos\r\nhimenaeos.\r\nDuis ac\r\nmassa\r\ninterdum,\r\ngravida ex\r\negestas,\r\nfinibus\r\npurus. Nunc\r\nconsectetur\r\ncommodo\r\nlacus, ac\r\nconvallis\r\nquam\r\nlobortis eu.\r\nSed\r\nconvallis\r\ntempor\r\ncommodo.\r\nNulla sed\r\nconvallis\r\nmauris.\r\nDonec\r\nvenenatis\r\nnisi est, ac\r\nullamcorper\r\nmi pretium\r\nquis. Donec\r\nvitae eros at\r\nipsum\r\ninterdum\r\nscelerisque\r\nnec vitae\r\nnisi. Sed\r\nvestibulum\r\nerat ac\r\nbibendum\r\ndapibus.\r\nMorbi nec\r\nelit id quam\r\ntristique\r\ncursus id\r\nsed sem.\r\nPraesent\r\nnon ante\r\nenim.\r\nPellentesqu\r\ne habitant\r\nmorbi\r\ntristique\r\nsenectus et\r\nnetus et\r\nmalesuada\r\nfames ac\r\nturpis\r\negestas.\r\nPraesent\r\nnon mauris\r\ndui.\r\nAliquam\r\nrhoncus\r\nmattis ante\r\nsed\r\nvenenatis.\r\nVivamus\r\nvehicula\r\nsed sapien\r\nsed dictum.\r\nIn aliquet,\r\nurna\r\nefficitur\r\ntincidunt\r\nlobortis,\r\nnibh justo\r\ntristique\r\npurus, sed\r\nvolutpat\r\nrisus magna\r\net\r\nlibero.Susp\r\nendisse\r\nlectus justo,\r\nvarius eget\r\narcu et,\r\nsemper\r\nlaoreet erat.\r\nQuisque\r\neget lacus\r\nornare,\r\npellentesqu\r\ne erat sit\r\namet,\r\nvulputate\r\nfelis. Duis\r\nluctus,\r\nmassa a\r\npellentesqu\r\ne mollis,\r\nmassa elit\r\nconvallis\r\nmi, vel\r\nbibendum\r\nex ex eu\r\npurus.\r\nSuspendiss\r\ne vel\r\nfermentum\r\nurna, ac\r\ncommodo\r\nenim.\r\nMauris\r\ntincidunt\r\ncursus elit,\r\na volutpat\r\nlibero\r\ncommodo\r\net. Etiam\r\ndapibus\r\nlibero\r\nvenenatis\r\ntellus\r\nlobortis, vel\r\nlacinia elit\r\nfaucibus.\r\nMaecenas\r\nsemper sed\r\nquam quis\r\nfinibus.\r\nInteger\r\nefficitur,\r\nlibero\r\nimperdiet\r\nsollicitudin\r\ncommodo,\r\nelit arcu\r\nvulputate\r\nest, eget\r\nfinibus mi\r\nurna sit\r\namet\r\nmagna.\r\nCras\r\nullamcorper\r\nconsequat\r\nornare.\r\nFusce\r\nconvallis\r\nnunc vel\r\nrisus\r\ncursus, at\r\nmaximus\r\nligula\r\ncursus.\r\nPellentesqu\r\ne vulputate\r\nrisus libero,\r\neget cursus\r\nnibh\r\nsodales\r\nsed. Donec\r\naccumsan\r\nsem et\r\nmassa\r\nsemper, id\r\ndignissim\r\nvelit\r\nvehicula.Cr\r\nas cursus\r\nipsum ac\r\nerat\r\nvehicula,\r\nnec iaculis\r\npurus\r\ndictum.\r\nQuisque\r\nlacinia elit\r\nvitae leo\r\ndictum, vel\r\ndignissim\r\nvelit\r\ndapibus.\r\nAenean sem\r\nnisi,\r\nfaucibus\r\ninterdum\r\njusto eu,\r\neuismod\r\nporttitor ex.\r\nMorbi et\r\nlectus\r\nlectus. Duis\r\nneque felis,\r\nsuscipit at\r\nscelerisque\r\neu,\r\nscelerisque\r\nid orci.\r\nCurabitur et\r\nplacerat\r\nipsum.\r\nProin\r\ngravida\r\nsapien nisl,\r\net varius\r\nipsum\r\nmollis nec.\r\nQuisque\r\ndignissim\r\nconsectetur\r\nfeugiat.\r\nAenean\r\neros purus,\r\nlaoreet\r\ninterdum\r\nrutrum at,\r\naliquet sit\r\namet\r\nlectus.\r\nDonec\r\ngravida\r\nlorem ut\r\ntincidunt\r\nlaoreet.\r\nDonec\r\nconsequat\r\nviverra\r\nligula, in\r\naccumsan\r\nmi\r\nbibendum\r\nscelerisque.\r\nQuisque ac\r\nrisus justo.\r\nMorbi\r\nmagna\r\narcu,\r\negestas nec\r\nluctus\r\ncommodo,\r\ncursus eget\r\nnunc.\r\nVivamus\r\neuismod\r\nlorem ex, et\r\nmaximus\r\nfelis\r\nhendrerit\r\neget.\r\nNullam\r\nullamcorper\r\neuismod\r\nligula, et\r\niaculis\r\nligula\r\nultricies a.\r\nFusce\r\naliquam,\r\nenim vel\r\nfermentum\r\nultrices, elit\r\nquam\r\nsemper\r\nerat, vitae\r\nsemper velit\r\naugue non\r\nmagna.Quis\r\nque\r\nmaximus\r\nsemper\r\narcu, id\r\npellentesqu\r\ne est\r\ntempus a.\r\nPhasellus\r\nlacus elit,\r\nauctor sit\r\namet lacinia\r\na, dapibus\r\nvitae velit.\r\nPhasellus ut\r\npharetra\r\njusto, ut\r\nultricies\r\nerat. Sed\r\nmolestie\r\nsapien vel\r\ninterdum\r\nlobortis.\r\nNulla\r\nfacilisi.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nnec mauris\r\nquis nisi\r\nvulputate\r\ngravida quis\r\nnec\r\nvelit.Nam et\r\ncongue\r\nipsum.\r\nNulla vel elit\r\nnon dolor\r\nmollis\r\naliquet vel\r\nat magna.\r\nPellentesqu\r\ne nec\r\nfacilisis elit.\r\nIn vulputate\r\nquis sem\r\nporta\r\nsuscipit.\r\nNullam sed\r\nex ornare\r\nnibh\r\nsuscipit\r\nmattis quis\r\nnon lacus.\r\nMauris vel\r\nex urna.\r\nVivamus\r\nultricies\r\nsapien sit\r\namet sapien\r\nvehicula\r\ngravida.\r\nDonec\r\nfeugiat\r\nvolutpat\r\nquam.\r\nVestibulum\r\nauctor\r\ndictum nisl,\r\nid hendrerit\r\nmetus\r\nullamcorper\r\nsed. Nulla\r\nmaximus\r\nlacus vel\r\nmollis\r\nmaximus.\r\nNulla\r\nlaoreet\r\nplacerat\r\nquam eu\r\nviverra.\r\nEtiam\r\nfeugiat\r\naccumsan\r\nnisl a\r\ncondimentu\r\nm. Sed\r\nultricies\r\nante ante,\r\nac auctor\r\nligula\r\ngravida nec.\r\nPraesent a\r\nneque\r\ndignissim,\r\nsagittis felis\r\nsit amet,\r\ncondimentu\r\nm turpis.\r\nFusce at leo\r\nvel est\r\nblandit\r\nmalesuada.\r\nPellentesqu\r\ne et neque\r\nnon metus\r\npellentesqu\r\ne imperdiet.\r\nPraesent\r\npellentesqu\r\ne lacinia\r\nlorem, et\r\ntristique\r\ntellus\r\nefficitur id.\r\nSuspendiss\r\ne aliquet\r\nultricies\r\njusto vitae\r\ninterdum.\r\nCras\r\ntristique\r\nviverra\r\nquam, eget\r\ngravida mi\r\nfermentum\r\nimperdiet.\r\nSed\r\nimperdiet\r\nvitae purus\r\nut volutpat.\r\nNulla\r\nlacinia elit\r\nin\r\nfermentum\r\nconsectetur\r\n. Phasellus\r\ncommodo\r\nut nisl sit\r\namet\r\nsagittis.\r\nDuis ac\r\nornare orci.\r\nVivamus vel\r\nenim\r\nposuere,\r\npharetra ex\r\nvel,\r\nelementum\r\nest.\r\nVestibulum\r\ncommodo\r\nluctus\r\nmetus eget\r\nmaximus.\r\nSuspendiss\r\ne a nulla a\r\nodio\r\neleifend\r\nfaucibus.\r\nSuspendiss\r\ne semper\r\nlacus non\r\nporttitor\r\naliquet.\r\nCras ac\r\nscelerisque\r\nmagna, et\r\npulvinar\r\njusto.\r\nInteger\r\ncursus\r\npulvinar\r\nfringilla.\r\nMauris\r\nimperdiet\r\nnibh sit\r\namet\r\ntempor\r\nlaoreet.\r\nMorbi\r\ntincidunt\r\ntortor ex, sit\r\namet\r\nmaximus\r\npurus\r\ntristique\r\nquis.\r\nQuisque\r\nsed\r\nhendrerit\r\nvelit. Mauris\r\nmattis nibh\r\nut eros\r\nluctus, eget\r\nmattis\r\nmassa\r\nauctor.\r\nPhasellus\r\neu neque at\r\naugue\r\ngravida\r\nsagittis nec\r\nnon tortor.\r\nEtiam\r\nporttitor\r\nsem\r\nsodales mi\r\nullamcorper\r\ngravida. In\r\nin dictum\r\norci. In vitae\r\nvestibulum\r\nquam. Cras\r\naugue eros,\r\ntincidunt ac\r\nelit posuere,\r\nsollicitudin\r\nefficitur\r\nlectus.\r\nPraesent\r\nquis\r\nsodales\r\nnisl. Proin\r\nsit amet\r\nmolestie\r\nest. In\r\ncommodo\r\nmauris vel\r\nmauris\r\nefficitur,\r\nnec mollis\r\nmauris\r\nsagittis.\r\nCras ligula\r\nnibh,\r\negestas sit\r\namet eros\r\nin, lacinia\r\ntristique\r\nmagna.\r\nCras risus\r\nlibero,\r\nlacinia eget\r\nlibero vitae,\r\nmaximus\r\naliquet\r\nnibh. Mauris\r\nid sodales\r\npurus, vitae\r\ndictum\r\nlectus. Cras\r\nconsectetur\r\nligula velit,\r\ntempus\r\npulvinar\r\nlacus\r\nporttitor\r\nvitae.\r\nPhasellus\r\neget tellus\r\nipsum.\r\nDonec\r\ninterdum\r\nlaoreet elit\r\nnon\r\nvestibulum.\r\nCras sed\r\nurna\r\nullamcorper\r\n, aliquam\r\nerat eget,\r\nporta orci.\r\nVestibulum\r\neget congue\r\nnulla. Sed\r\nsem tortor,\r\neuismod at\r\nrutrum id,\r\nsagittis a\r\nnunc. Duis\r\nin nibh\r\nfacilisis,\r\ndignissim\r\npurus ut,\r\nhendrerit\r\nmagna. Sed\r\nsemper\r\nligula id\r\nmassa\r\nelementum,\r\nnon\r\nmalesuada\r\nvelit\r\negestas.\r\nNullam\r\ndictum, mi\r\nnec\r\neuismod\r\nsagittis,\r\nligula leo\r\nullamcorper\r\ndolor, quis\r\nfaucibus\r\nodio metus\r\neget magna.\r\nUt gravida\r\nmetus non\r\nmetus\r\nbibendum\r\nbibendum.\r\nIn sagittis\r\neleifend\r\naliquet.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNam mollis\r\nsagittis\r\nfelis, in\r\nfaucibus\r\ntortor\r\npretium vel.\r\nNam nec\r\nenim\r\nmetus.\r\nDonec in\r\naugue arcu.\r\nProin non\r\nlobortis\r\npurus, sit\r\namet lacinia\r\nelit.\r\nSuspendiss\r\ne quis eros\r\ncondimentu\r\nm, blandit\r\njusto sit\r\namet,\r\nlobortis nisl.\r\nSuspendiss\r\ne maximus\r\nmassa sed\r\nurna tempor\r\nornare.\r\nNunc\r\nmalesuada\r\npurus odio,\r\neu luctus\r\nlectus\r\nauctor nec.\r\nMorbi\r\nauctor\r\npellentesqu\r\ne auctor.\r\nSed\r\nullamcorper\r\n, ex vitae\r\naliquam\r\nvulputate,\r\nest diam\r\nfeugiat mi,\r\nid porttitor\r\nlectus orci\r\nac leo.\r\nDonec sit\r\namet velit\r\npulvinar,\r\nvenenatis\r\nturpis ut,\r\ninterdum\r\nligula.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nVestibulum\r\neu lacus\r\nurna.\r\nMaecenas\r\nsem nulla,\r\naccumsan\r\neu ultricies\r\nsed, tempor\r\nvel magna.\r\nCras aliquet\r\nsollicitudin\r\nsapien ac\r\npulvinar.\r\nPraesent ac\r\nsodales mi.\r\nInteger vitae\r\nmauris\r\nmassa.\r\nMaecenas\r\niaculis orci\r\net faucibus\r\ninterdum.\r\nNunc nec\r\nmaximus\r\nfelis, sed\r\nfinibus\r\nquam.\r\nPellentesqu\r\ne felis\r\nmassa,\r\nvestibulum\r\nin tellus\r\nvitae,\r\ncongue\r\ntincidunt\r\njusto. Nunc\r\nvitae enim\r\nmalesuada,\r\nbibendum\r\nante nec,\r\nvarius\r\ntellus.\r\nPraesent\r\nvitae nisi id\r\nquam\r\nauctor\r\nlacinia at\r\nnon quam.\r\nNam nec\r\nligula sit\r\namet felis\r\nauctor\r\nsagittis.\r\nNunc in\r\nrisus eu\r\nurna varius\r\nlaoreet quis\r\nsit amet\r\nfelis. Morbi\r\nvarius\r\ntempor orci,\r\neu\r\nvestibulum\r\nnunc\r\nvestibulum\r\nac. Nunc\r\nvehicula\r\nvelit\r\neleifend\r\nconsequat\r\nporta.\r\nSuspendiss\r\ne maximus\r\ndapibus\r\norci, in\r\nvulputate\r\nmassa\r\npretium ac.\r\nQuisque\r\nmalesuada\r\naliquet\r\naliquet."; + + var mf = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Style = MeasurementFontStyles.Regular, + Size = 11.0f, + }; + + var handler = new TextHandler(SystemFolderEngine, mf); + + double maxPixelWidth = 72d; + + List fragments = new List() { Lorem20Str }; + List fonts = new List() { mf }; + + //TextFragmentCollectionSimple collection = new TextFragmentCollectionSimple(fonts, fragments); + + var pointWidth = 54.085732283464566929133858267717f; + + var wrappedStrings = handler.WrapText(Lorem20Str, pointWidth); + var savedStrings = SavedComparisonString.Split(new string[] { "\r\n" }, StringSplitOptions.None); + + List differingStrings = new(); + + if (wrappedStrings.Count() > savedStrings.Count()) + differingStrings = savedStrings.Except(wrappedStrings).ToList(); + else + differingStrings = wrappedStrings.Except(savedStrings).ToList(); + + ////INTENTIONAL COMMENT for easier debugging later. + ////It is sometimes easier to compare files directly when debugging rather than looking through "differingStrings" + //bool writeFiles = true; + + //if (/*differingStrings.Count() > 0*/ writeFiles) + ////{ + File.WriteAllText("C:\\temp\\LoremIpsum20_NEW.txt", string.Join("\r\n", wrappedStrings.ToArray())); + File.WriteAllText("C:\\temp\\LoremIpsum20_OLD.txt", SavedComparisonString); + + var currStr = File.ReadAllText("C:\\temp\\LoremIpsum20_NEW.txt"); + + var res = SavedComparisonString.CompareTo(currStr); + + Assert.AreEqual(SavedComparisonString, currStr); + ////} + + Assert.AreEqual(0, differingStrings.Count()); + } + } +} diff --git a/src/EPPlus.DrawingRenderer.Tests/TextRenderTests.cs b/src/EPPlus.DrawingRenderer.Tests/TextRenderTests.cs new file mode 100644 index 0000000000..d04da9f575 --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/TextRenderTests.cs @@ -0,0 +1,390 @@ +//using EPPlus.Export.ImageRenderer.ChartAreaRenderItems.SvgItem; +//using EPPlus.Fonts.OpenType; +//using EPPlus.Fonts.OpenType.Integration; +//using EPPlus.Fonts.OpenType.Utils; +//using EPPlus.Graphics; +//using EPPlusImageRenderer; +//using EPPlusImageRenderer.Svg; +//using OfficeOpenXml; +//using OfficeOpenXml.Drawing; +//using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +//using OfficeOpenXml.Interfaces.Drawing.Text; +//using OfficeOpenXml.Style; +//using System.Diagnostics; +//using System.Globalization; +//using System.Runtime.InteropServices; +//using System.Text; + +//namespace EPPlus.Export.ImageRenderer.Tests +//{ +// [TestClass] +// public sealed class TextRenderTests : TestBase +// { +// private void SetFillColor(ExcelDrawingFillBasic fill, string color) +// { +// if (color.StartsWith("#")) +// { +// fill.Style = eFillStyle.SolidFill; +// var r = int.Parse(color.Substring(1, 2), NumberStyles.HexNumber); +// var g = int.Parse(color.Substring(3, 2), NumberStyles.HexNumber); +// var b = int.Parse(color.Substring(5, 2), NumberStyles.HexNumber); +// var c = System.Drawing.Color.FromArgb(0xFF, (byte)r, (byte)g, (byte)b); +// fill.SolidFill.Color.SetRgbColor(c); +// } +// else if (string.IsNullOrWhiteSpace(color) == false) +// { +// fill.Style = eFillStyle.SolidFill; +// try +// { +// var c = System.Drawing.Color.FromName(color); +// if (c.IsEmpty) +// { +// var sc = Enum.Parse(color); +// fill.SolidFill.Color.SetSchemeColor(sc); +// } +// else +// { +// fill.SolidFill.Color.SetPresetColor(c); +// } +// } +// catch +// { +// var sc = Enum.Parse(color); +// fill.SolidFill.Color.SetSchemeColor(sc); +// } +// } +// else +// { +// fill.Style = eFillStyle.NoFill; +// } +// } + +// //TextFragmentCollectionSimple GenerateTextFragments(ExcelDrawingTextRunCollection runs) +// //{ +// // List runContents = new List(); +// // List fontSizes = new List(); +// // List fonts = new List(); + +// // for (int i = 0; i < runs.Count(); i++) +// // { +// // var txtRun = runs[i]; +// // var runFont = txtRun.GetMeasurementFont(); + +// // fonts.Add(runFont); + +// // runContents.Add(txtRun.Text); +// // fontSizes.Add(runFont.Size); +// // } + + +// // return new TextFragmentCollectionSimple(fonts, runContents); +// //} + +// //List GetWrappedText(ExcelDrawingTextRunCollection runs, TextFragmentCollectionSimple fragments) +// //{ + +// // List fonts = new List(); + +// // for (int i = 0; i < runs.Count(); i++) +// // { +// // var txtRun = runs[i]; +// // var runFont = txtRun.GetMeasurementFont(); +// // fonts.Add(runFont); +// // } + +// // var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); +// // TextHandler handler = new TextHandler(fonts[0]); + +// // return handler.WrapMultipleTextFragmentsToTextLines(fragments, fonts, maxSizePoints); +// //} + +// [TestMethod] +// public void MeasureWrappedWidths() +// { +// List lstOfRichText = new() { /*"RenderTextbox\r\na",*/ "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + +// //var font1 = new MeasurementFont() +// //{ +// // FontFamily = "Aptos Narrow", +// // Size = 11, +// // Style = MeasurementFontStyles.Regular +// //}; ; + +// var font2 = new MeasurementFont() +// { +// FontFamily = "Aptos Narrow", +// Size = 11, +// Style = MeasurementFontStyles.Italic | MeasurementFontStyles.Bold +// }; + +// var font3 = new MeasurementFont() +// { +// FontFamily = "Aptos Narrow", +// Size = 11, +// Style = MeasurementFontStyles.Underline +// }; + +// var font4 = new MeasurementFont() +// { +// FontFamily = "Aptos Narrow", +// Size = 11, +// Style = MeasurementFontStyles.Strikeout +// }; + +// var font5 = new MeasurementFont() +// { +// FontFamily = "Goudy Stout", +// Size = 16, +// Style = MeasurementFontStyles.Regular +// }; + + +// var font6 = new MeasurementFont() +// { +// FontFamily = "Aptos Narrow", +// Size = 24, +// Style = MeasurementFontStyles.Regular +// }; + +// List fonts = new() { /*font1,*/ font2, font3, font4, font5, font6}; + +// var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); +// var ttMeasurer = OpenTypeFonts.GetTextLayoutEngineForFont(font2); + +// var textFragments = new TextFragmentCollectionSimple(fonts, lstOfRichText); + +// var wrappedLines = ttMeasurer.WrapRichTextLines(textFragments, maxSizePoints); + +// //Assert.AreEqual(wrappedLines[0].r) + + +// //Line 1 45 px 34.5pt +// //Line 2 6px 4.5 pt +// //Line 3 137 px 102.75 pt //result: 104.6328125 pt width "whole +// //Line 4 270 px 202.5 pt +// //Line 5 169 px 126.75 pt +// } + +// [TestMethod] +// public void VerifyTextRunBounds() +// { +// ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + +// using (var p = new ExcelPackage()) +// { +// var ws = p.Workbook.Worksheets.Add("Sheet1"); +// var cube = ws.Drawings.AddShape("Cube1", OfficeOpenXml.Drawing.eShapeStyle.Cube); + +// cube.Font.Color = System.Drawing.Color.Goldenrod; + +// cube.TextBody.TopInsert = 0; +// cube.TextBody.BottomInsert = 0; +// cube.TextBody.RightInsert = 0; +// cube.TextBody.LeftInsert = 0; + +// var para1 = cube.TextBody.Paragraphs.Add("TextBox\r\na"); + +// para1.LeftMargin = 5; +// cube.TextBody.TopInsert = 10; + +// var para2 = cube.TextBody.Paragraphs.Add("TextBox2"); +// para2.TextRuns[0].FontItalic = true; +// para2.TextRuns[0].FontBold = true; +// para2.TextRuns.Add("ra underline").FontUnderLine = eUnderLineType.Dash; +// para2.TextRuns.Add("La Strike").FontStrike = eStrikeType.Single; +// var tRun1 = para2.TextRuns.Add("Goudy size 16"); +// tRun1.SetFromFont("Goudy Stout", 16); +// tRun1.Fill.Color = System.Drawing.Color.IndianRed; +// var tRun2 = para2.TextRuns.Add("SvgSize 24"); +// tRun2.FontSize = 24; + +// cube.TextAlignment = eTextAlignment.Left; +// cube.TextAnchoring = eTextAnchoringType.Top; + +// cube.TextBody.HorizontalTextOverflow = eTextHorizontalOverflow.Clip; +// cube.TextBody.VerticalTextOverflow = eTextVerticalOverflow.Clip; + +// SetFillColor(cube.Fill, "#156082"); +// SetFillColor(cube.Border.Fill, "#042433"); + +// var aFont = cube.Font; +// var paragraph0 = cube.TextBody.Paragraphs[0]; + +// var autofit = cube.TextBody.TextAutofit; + +// cube.ChangeCellAnchor(eEditAs.Absolute); + +// cube.SetPixelWidth(5000); +// var svgShape = new SvgShape(cube); +// SvgTextBodyItem tbItem = svgShape.TextBodySvg; + +// var txtRun1Bounds = tbItem.Paragraphs[0].Runs[0].Bounds; +// var pxWidth = txtRun1Bounds.Width.PointToPixel(); +// Assert.AreEqual(43.835286458333336d, pxWidth, 0.2d); + +// var txtRuns2 = tbItem.Paragraphs[1].Runs; + +// Assert.AreEqual(53.20963541666667d, txtRuns2[0].Bounds.Width.PointToPixel(),0.2); +// var currentLineWidth = txtRuns2[0].Bounds.Width.PointToPixel(); + +// Assert.AreEqual(currentLineWidth, txtRuns2[1].Bounds.Left.PointToPixel(),0.2); +// Assert.AreEqual(69.55924479166667d, txtRuns2[1].Bounds.Width.PointToPixel(),0.2); +// currentLineWidth += txtRuns2[1].Bounds.Width.PointToPixel(); + +// Assert.AreEqual(currentLineWidth, txtRuns2[2].Bounds.Left.PointToPixel(),0.0001); +// Assert.AreEqual(49.89388020833334, txtRuns2[2].Bounds.Width.PointToPixel(), 0.0001); +// currentLineWidth += txtRuns2[2].Bounds.Width.PointToPixel(); + +// Assert.AreEqual(21.333333333333332, txtRuns2[3].Bounds.Height.PointToPixel()); +// Assert.AreEqual(currentLineWidth, txtRuns2[3].Bounds.Left.PointToPixel(), 0.0001); +// Assert.AreEqual(283.21875d, txtRuns2[3].Bounds.Width.PointToPixel(), 0.0001); +// currentLineWidth += txtRuns2[3].Bounds.Width.PointToPixel(); + +// Assert.AreEqual(32, txtRuns2[4].Bounds.Height.PointToPixel(), 0.0001); +// Assert.AreEqual(currentLineWidth, txtRuns2[4].Bounds.Left.PointToPixel(), 0.0001); +// Assert.AreEqual(134.20312500000006d, txtRuns2[4].Bounds.Width.PointToPixel(), 0.0001); +// currentLineWidth += txtRuns2[4].Bounds.Width.PointToPixel(); +// } +// } + +// private ExcelShape GenerateTextShapeWithDifficultText(ExcelPackage p) +// { +// var myCulture = CultureInfo.CurrentCulture; + +// var ws = p.Workbook.Worksheets.Add("ShapeSheet"); + +// var cube = ws.Drawings.AddShape("myCube", eShapeStyle.Cube); + +// cube.Fill.Style = eFillStyle.SolidFill; +// cube.Fill.Color = System.Drawing.Color.BlueViolet; +// cube.Font.Color = System.Drawing.Color.Goldenrod; + +// cube.TextBody.TopInsert = 0; +// cube.TextBody.BottomInsert = 0; +// cube.TextBody.RightInsert = 0; +// cube.TextBody.LeftInsert = 0; + +// var para1 = cube.TextBody.Paragraphs.Add("TextBodySvg\r\na"); + +// var para2 = cube.TextBody.Paragraphs.Add("TextBox2"); +// para2.TextRuns[0].FontItalic = true; +// para2.TextRuns[0].FontBold = true; +// para2.TextRuns.Add("ra underline").FontUnderLine = eUnderLineType.Dash; +// para2.TextRuns.Add("La Strike").FontStrike = eStrikeType.Single; +// var tRun1 = para2.TextRuns.Add("Goudy size 16"); +// tRun1.SetFromFont("Goudy Stout", 16); + +// tRun1.Fill.Color = System.Drawing.Color.IndianRed; +// var tRun2 = para2.TextRuns.Add("SvgSize 24"); +// tRun2.FontSize = 24; + +// cube.TextBody.HorizontalTextOverflow = eTextHorizontalOverflow.Clip; +// cube.TextBody.VerticalTextOverflow = eTextVerticalOverflow.Clip; + +// var aFont = cube.Font; +// var paragraph0 = cube.TextBody.Paragraphs[0]; + +// var autofit = cube.TextBody.TextAutofit; + +// cube.ChangeCellAnchor(eEditAs.Absolute); + +// cube.GetSizeInPixels(out int testWidth, out int testHeight); + +// cube.SetPixelHeight(400); +// cube.SetPixelWidth(400); + +// return cube; +// } + + +// [TestMethod] +// public void VerifyVerticalAlignTop() +// { +// ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + +// using var p = new ExcelPackage(); +// var shape = GenerateTextShapeWithDifficultText(p); + +// shape.TextAnchoring = eTextAnchoringType.Top; + +// var svgShape = new SvgShape(shape); +// SvgTextBodyItem tbItem = svgShape.TextBodySvg; + +// Assert.AreEqual(100, tbItem.Bounds.GlobalTop.PointToPixel()); +// } + +// [TestMethod] +// public void VerifyVerticalAlignCenter() +// { +// ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + +// using var p = new ExcelPackage(); +// var shape = GenerateTextShapeWithDifficultText(p); + +// shape.TextAnchoring = eTextAnchoringType.Center; + +// var svgShape = new SvgShape(shape); +// SvgTextBodyItem tbItem = svgShape.TextBodySvg; + + +// //Appears off by 1-2 px bc of border width +// Assert.AreEqual(190d, tbItem.Bounds.GlobalTop.PointToPixel() , 1.0); +// } + + +// [TestMethod] +// public void VerifyVerticalAlignBottom() +// { +// ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + +// using var p = new ExcelPackage(); +// var shape = GenerateTextShapeWithDifficultText(p); + +// shape.TextAnchoring = eTextAnchoringType.Bottom; + +// var svgShape = new SvgShape(shape); +// SvgTextBodyItem tbItem = svgShape.TextBodySvg; + +// var ir = new EPPlusImageRenderer.ImageRenderer(); +// var svg = ir.RenderDrawingToSvg(shape); +// SaveTextFileToWorkbook("bottom.svg", svg); +// SaveWorkbook("vaBottom.xlsx", p); +// //Appears off by ~2 px because of border width +// Assert.AreEqual(278d, tbItem.Bounds.GlobalTop.PointToPixel(), 1.0); +// } + +// [TestMethod] +// public void AddTextPosition() +// { +// ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + +// using var p = new ExcelPackage(); +// var shape = GenerateTextShapeWithDifficultText(p); + +// shape.TextAnchoring = eTextAnchoringType.Center; + +// var svgShape = new SvgShape(shape); +// SvgTextBodyItem tbItem = svgShape.TextBodySvg; + + +// var sb = new StringBuilder(); +// var lastpara = tbItem.Paragraphs.Last(); + +// MeasurementFont font = new MeasurementFont +// { +// FontFamily = "Aptos Narrow", +// Size = 11, +// Style = MeasurementFontStyles.Bold +// }; + +// //var trItem = new SvgTextRunItem(svgShape, lastpara.Bounds, font, "MyText"); +// //lastpara.Runs.Add(trItem); +// lastpara.AddOwnText(new TextFragment() {Text = "my new text", Font = font }); +// svgShape.Render(sb); + +// var str = sb.ToString(); + +// SaveTextFileToWorkbook("InsertedTextTest.svg", str); +// } +// } +//} diff --git a/src/EPPlus.DrawingRenderer.Tests/TextboxTest.cs b/src/EPPlus.DrawingRenderer.Tests/TextboxTest.cs new file mode 100644 index 0000000000..daa8beb25e --- /dev/null +++ b/src/EPPlus.DrawingRenderer.Tests/TextboxTest.cs @@ -0,0 +1,74 @@ +//using EPPlus.Export.ImageRenderer.ChartAreaRenderItems.SvgItem; +//using EPPlus.Export.ImageRenderer.Svg; +//using EPPlus.Graphics; +//using EPPlusImageRenderer.ChartAreaRenderItems; +//using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; + +//namespace EPPlus.Export.ImageRenderer.Tests +//{ +// [TestClass] +// public class TextboxTest : TestBase +// { +// [TestMethod] +// public void TextBoxVerification() +// { +// var baseBB = new BoundingBox(); + +// //96x96 px +// baseBB.Width = 72; +// baseBB.Height = 72; + +// var item = new DrawingItemForTesting(baseBB); + +// BoundingBox maxBounds = new BoundingBox(); +// maxBounds.Width = 36; +// maxBounds.Height = 36; + +// var txtBox = new SvgTextBox(item, item.Bounds, maxBounds); +// txtBox.AddText(0, "My new text which is fun"); +// txtBox.Rectangle.FillColor = "red"; +// txtBox.Rectangle.FillOpacity = 0.2d; + +// txtBox.Left = 5; +// txtBox.Top = 5; + +// item.ExternalRenderItemsNoBounds.Add(txtBox); + +// var txtBoxNotMaxed = new SvgTextBox(item, item.Bounds, maxBounds); +// txtBoxNotMaxed.Left = 42; +// txtBoxNotMaxed.Top = 5; + +// txtBoxNotMaxed.AddText(0, "abc"); +// txtBoxNotMaxed.Rectangle.FillColor = "yellow"; +// txtBoxNotMaxed.Rectangle.FillOpacity = 0.2d; + +// item.ExternalRenderItemsNoBounds.Add(txtBoxNotMaxed); + +// var sb = new StringBuilder(); + +// item.Render(sb); +// var svgString = sb.ToString(); + +// //before we assumed we consider the space widths +// var widthWithSpace = txtBox.TextBody.Paragraphs[0].SpaceWidthsPerLine[0] + txtBox.Width; + + +// //Assert.AreEqual(36d, txtBox.TextBody.Width); +// Assert.AreEqual(37.5d, widthWithSpace, 0.5); +// Assert.AreNotEqual(36d, txtBoxNotMaxed.Width); +// Assert.AreEqual(16.29052734375d, txtBoxNotMaxed.Width); + +// //var sb = new StringBuilder(); + +// //item.Render(sb); +// //var svgString = sb.ToString(); + +// SaveTextFileToWorkbook($"svg\\StandAloneTextBox.svg", svgString); +// } +// } +//} diff --git a/src/EPPlus.DrawingRenderer/AdjustmentType.cs b/src/EPPlus.DrawingRenderer/AdjustmentType.cs new file mode 100644 index 0000000000..0c1912a58b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/AdjustmentType.cs @@ -0,0 +1,23 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace EPPlus.DrawingRenderer +{ + internal enum AdjustmentType + { + AdjustToWidthHeight = 0, + LockToAdjustMin = 1, + LockToAdjustMax = 2, + Adjust = 255, + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ChartObjectMargins.cs b/src/EPPlus.DrawingRenderer/ChartObjectMargins.cs new file mode 100644 index 0000000000..8a1c0cca47 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ChartObjectMargins.cs @@ -0,0 +1,8 @@ +namespace EPPlus.DrawingRenderer +{ + internal static class ChartObjectMargins + { + static int TitleToPlotarea = 14; + static int LegendToPlotarea = 14; + } +} diff --git a/src/EPPlus.DrawingRenderer/Constants/Constants.cs b/src/EPPlus.DrawingRenderer/Constants/Constants.cs new file mode 100644 index 0000000000..a29202b7e4 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Constants/Constants.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.DrawingRenderer +{ + internal class Constants + { + internal const float STANDARD_DPI = 96; + /// + /// The ratio between EMU and Pixels + /// + public const int EMU_PER_PIXEL = 9525; + /// + /// The ratio between EMU and Points + /// + public const int EMU_PER_POINT = 12700; + /// + /// The ratio between EMU and centimeters + /// + public const int EMU_PER_CM = 360000; + /// + /// The ratio between EMU and millimeters + /// + public const int EMU_PER_MM = 3600000; + /// + /// The ratio between EMU and US Inches + /// + public const int EMU_PER_US_INCH = 914400; + /// + /// The ratio between EMU and pica + /// + public const int EMU_PER_PICA = EMU_PER_US_INCH / 6; + + } +} diff --git a/src/EPPlus.DrawingRenderer/Constants/PatternArrays.cs b/src/EPPlus.DrawingRenderer/Constants/PatternArrays.cs new file mode 100644 index 0000000000..0992f78af8 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Constants/PatternArrays.cs @@ -0,0 +1,402 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace DrawingRenderer.Constants +{ + internal static class PatternArrays + { + internal static readonly short[][] Pct30 = new short[][] + { + new short[] { 0, 0, 0, 1 }, + new short[] { 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 0 }, + new short[] { 1, 0, 1, 0 } + }; + + internal static readonly short[][] Pct40 = new short[][] + { + new short[] { 0, 0, 0, 1, 0, 1, 0, 1 }, + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 1, 0, 1 }, + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 0, 0, 1 }, + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 1, 0, 1 }, + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 } + }; + + internal static readonly short[][] Pct50 = new short[][] + { + new short[] { 1, 1, 1, 0 }, + new short[] { 0, 1, 0, 1 }, + new short[] { 1, 0, 1, 1 }, + new short[] { 0, 1, 0, 1 } + }; + + internal static readonly short[][] Pct60 = new short[][] + { + new short[] { 1, 1, 0, 1 }, + new short[] { 0, 1, 1, 1 } + }; + + internal static readonly short[][] Pct70 = new short[][] + { + new short[] { 1, 1, 0, 1 }, + new short[] { 1, 1, 1, 1 }, + new short[] { 0, 1, 1, 1 }, + new short[] { 1, 1, 1, 1 } + }; + + + internal static readonly short[][] LtHorz = new short[][] { + new short[] { 1 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 } + }; + + internal static readonly short[][] LtVert = new short[][] { + new short[] { 1, 0, 0, 0 } + }; + + internal static readonly short[][] LtUpDiag = new short[][] { + new short[] { 0, 0, 0, 1 }, + new short[] { 0, 0, 1, 0 }, + new short[] { 0, 1, 0, 0 }, + new short[] { 1, 0, 0, 0 } + }; + + internal static readonly short[][] LtDnDiag = new short[][] { + new short[] { 1, 0, 0, 0 }, + new short[] { 0, 1, 0, 0 }, + new short[] { 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 1 } + }; + + internal static readonly short[][] DkVert = new short[][] { + new short[] { 1, 1, 0, 0 } + }; + + internal static readonly short[][] DkHorz = new short[][] { + new short[] { 1 }, + new short[] { 1 }, + new short[] { 0 }, + new short[] { 0 } + }; + + + internal static readonly short[][] DkUpDiag = new short[][] { + new short[] { 1, 0, 0, 1 }, + new short[] { 0, 0, 1, 1 }, + new short[] { 0, 1, 1, 0 }, + new short[] { 1, 1, 0, 0 } + }; + + internal static readonly short[][] DkDnDiag = new short[][] { + new short[] { 1, 0, 0, 1 }, + new short[] { 1, 1, 0, 0 }, + new short[] { 0, 1, 1, 0 }, + new short[] { 0, 0, 1, 1 } + }; + + internal static readonly short[][] WdUpDiag = new short[][] { + new short[] { 1, 1, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 1 }, + new short[] { 0, 0, 0, 0, 0, 1, 1, 0 }, + new short[] { 0, 0, 0, 0, 1, 1, 0, 0 }, + new short[] { 0, 0, 0, 1, 1, 0, 0, 0 }, + new short[] { 0, 0, 1, 1, 0, 0, 0, 0 }, + new short[] { 0, 1, 1, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] WdDnDiag = new short[][] { + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 1, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 1, 1, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 1, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 1, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 1, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 1 } + }; + + internal static readonly short[][] NarVert = new short[][] { + new short[] { 1, 0 } + }; + + internal static readonly short[][] NarHorz = new short[][] { + new short[] { 1 }, + new short[] { 0 } + }; + + + internal static readonly short[][] Vert = new short[][] { + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] Horz = new short[][] { + new short[] { 1 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 }, + new short[] { 0 } + }; + + internal static readonly short[][] DashDnDiag = new short[][] { + new short[] { 1, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 1, 0, 0, 0, 1, 0, 0 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] DashUpDiag = new short[][] { + new short[] { 0, 1, 0, 0, 0, 1, 0, 0 }, + new short[] { 1, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 1 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 } + }; + + internal static readonly short[][] DashHorz = new short[][] { + new short[] { 0, 0, 0, 0, 1, 1, 1, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 1, 1, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] DashVert = new short[][] { + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 } + }; + + + internal static readonly short[][] SmConfetti = new short[][] { + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 1, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 1, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 1, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 0 } + }; + + internal static readonly short[][] LgConfetti = new short[][] { + new short[] { 0, 0, 0, 0, 0, 0, 1, 1 }, + new short[] { 0, 0, 0, 1, 1, 0, 1, 1 }, + new short[] { 1, 1, 0, 1, 1, 0, 0, 0 }, + new short[] { 1, 1, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 1, 0, 0 }, + new short[] { 1, 0, 0, 0, 1, 1, 0, 1 }, + new short[] { 1, 0, 1, 1, 0, 0, 0, 1 }, + new short[] { 0, 0, 1, 1, 0, 0, 0, 0 } + }; + + internal static readonly short[][] ZigZag = new short[][] { + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 1, 0, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 1, 0, 0, 1, 0, 0 }, + new short[] { 0, 0, 0, 1, 1, 0, 0, 0 } + }; + + internal static readonly short[][] Wave = new short[][] { + new short[] { 0, 0, 1, 0, 0, 1, 0, 1 }, + new short[] { 1, 1, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 1, 0, 0, 0 } + }; + + internal static readonly short[][] DiagBrick = new short[][] { + new short[] { 0, 0, 1, 0, 0, 1, 0, 0 }, + new short[] { 0, 1, 0, 0, 0, 0, 1, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 1, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 1, 0, 0, 0 } + }; + + internal static readonly short[][] HorzBrick = new short[][] { + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 1, 1, 1, 1, 1, 1, 1 } + }; + + internal static readonly short[][] Weave = new short[][] { + new short[] { 1, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 1, 0, 1, 0, 1, 0, 0 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 }, + new short[] { 0, 1, 0, 0, 0, 1, 0, 1 }, + new short[] { 1, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 1, 0, 0 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 0, 0, 1 } + }; + + internal static readonly short[][] Plaid = new short[][] { + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 1, 0, 1 }, + new short[] { 1, 1, 1, 1, 0, 0, 0, 0 }, + new short[] { 1, 1, 1, 1, 0, 0, 0, 0 }, + new short[] { 1, 1, 1, 1, 0, 0, 0, 0 }, + new short[] { 1, 1, 1, 1, 0, 0, 0, 0 }, + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 1, 0, 1, 0, 1, 0, 1 } + }; + + + internal static readonly short[][] Divot = new short[][] { + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] DotGrid = new short[][] { + new short[] { 1, 0, 1, 0, 1, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] DotDmnd = new short[][] { + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 1, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] Shingle = new short[][] { + new short[] { 0, 0, 1, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 1, 1, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 0, 0, 0, 0, 0, 0, 1, 1 }, + new short[] { 1, 0, 0, 0, 0, 1, 0, 0 }, + new short[] { 0, 1, 0, 0, 1, 0, 0, 0 } + }; + + internal static readonly short[][] Trellis = new short[][] { + new short[] { 0, 1, 1, 0 }, + new short[] { 1, 1, 1, 1 }, + new short[] { 1, 0, 0, 1 }, + new short[] { 1, 1, 1, 1 } + }; + + internal static readonly short[][] Sphere = new short[][] { + new short[] { 1, 0, 0, 1, 1, 0, 0, 0 }, + new short[] { 1, 1, 1, 1, 1, 0, 0, 0 }, + new short[] { 1, 1, 1, 1, 1, 0, 0, 0 }, + new short[] { 0, 1, 1, 1, 0, 1, 1, 1 }, + new short[] { 1, 0, 0, 0, 1, 0, 0, 1 }, + new short[] { 1, 0, 0, 0, 1, 1, 1, 1 }, + new short[] { 1, 0, 0, 0, 1, 1, 1, 1 }, + new short[] { 0, 1, 1, 1, 0, 1, 1, 1 } + }; + + internal static readonly short[][] SmGrid = new short[][] { + new short[] { 1, 1, 1, 1 }, + new short[] { 1, 0, 0, 0 }, + new short[] { 1, 0, 0 }, + new short[] { 1, 0, 0, 0 } + }; + + internal static readonly short[][] LgGrid = new short[][] { + new short[] { 1, 1, 1, 1, 1, 1, 1, 1 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 0, 0 } + }; + + internal static readonly short[][] SmCheck = new short[][] { + new short[] { 1, 0, 0, 1 }, + new short[] { 1, 0, 0, 1 }, + new short[] { 0, 1, 1, 0 }, + new short[] { 0, 1, 1, 0 } + }; + + internal static readonly short[][] LgCheck = new short[][] { + new short[] { 1, 1, 0, 0, 0, 0, 1, 1 }, + new short[] { 1, 1, 0, 0, 0, 0, 1, 1 }, + new short[] { 0, 0, 1, 1, 1, 1, 0, 0 }, + new short[] { 0, 0, 1, 1, 1, 1, 0, 0 }, + new short[] { 0, 0, 1, 1, 1, 1, 0, 0 }, + new short[] { 0, 0, 1, 1, 1, 1, 0, 0 }, + new short[] { 1, 1, 0, 0, 0, 0, 1, 1 }, + new short[] { 1, 1, 0, 0, 0, 0, 1, 1 } + }; + + internal static readonly short[][] OpenDmnd = new short[][] { + new short[] { 0, 1, 0, 0, 0, 1, 0, 0 }, + new short[] { 1, 0, 0, 0, 0, 0, 1, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new short[] { 1, 0, 0, 0, 0, 0, 1, 0 }, + new short[] { 0, 1, 0, 0, 0, 1, 0, 0 }, + new short[] { 0, 0, 1, 0, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 1, 0, 1, 0, 0, 0 } + }; + + internal static readonly short[][] SolidDmnd = new short[][] { + new short[] { 0, 1, 1, 1, 1, 1, 0, 0 }, + new short[] { 0, 0, 1, 1, 1, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 0, 0, 1, 0, 0, 0, 0 }, + new short[] { 0, 0, 1, 1, 1, 0, 0, 0 }, + new short[] { 0, 1, 1, 1, 1, 1, 0, 0 }, + new short[] { 1, 1, 1, 1, 1, 1, 1, 0 } + }; + + } +} diff --git a/src/EPPlus.DrawingRenderer/Coordinate.cs b/src/EPPlus.DrawingRenderer/Coordinate.cs new file mode 100644 index 0000000000..7aa56ae67d --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Coordinate.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace EPPlus.DrawingRenderer +{ + public class Coordinate + { + public Coordinate(double x, double y) + { + X = x; + Y = y; + } + public double X { get; set; } + public double Y { get; set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.csproj b/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.csproj new file mode 100644 index 0000000000..7643545c66 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.csproj @@ -0,0 +1,41 @@ + + + net8.0;net9.0;net10.0;netstandard2.1;netstandard2.0;net462 + 9.0.0.0 + 9.0.0.0 + 9.0.0.0 + enable + enable + EPPlus Software AB + EPPlus + A spreadsheet library for .NET framework and .NET core + + latest + True + EPPlus.DrawingRenderer.snk + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + diff --git a/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.snk b/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.snk new file mode 100644 index 0000000000..8a53d24382 Binary files /dev/null and b/src/EPPlus.DrawingRenderer/EPPlus.DrawingRenderer.snk differ diff --git a/src/EPPlus.DrawingRenderer/Properties/AssemblyInfo.cs b/src/EPPlus.DrawingRenderer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..5ee4e11884 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Properties/AssemblyInfo.cs @@ -0,0 +1,15 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using System.Security; + +[assembly: AllowPartiallyTrustedCallers] diff --git a/src/EPPlus.DrawingRenderer/RenderContext.cs b/src/EPPlus.DrawingRenderer/RenderContext.cs new file mode 100644 index 0000000000..fa2ebd031f --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderContext.cs @@ -0,0 +1,51 @@ +using EPPlus.Fonts.OpenType; + +namespace EPPlus.DrawingRenderer +{ + /// + /// Carries rendering-wide resources down the drawing render stack (DrawingRenderer and + /// below), independent of output format (SVG, PDF). Owned by the workbook, created once + /// per workbook. The font engine is lazy-loaded on first use so constructing the context + /// is cheap; the expensive engine (and its font cache) is only built when something is + /// actually rendered. + /// + public class RenderContext : IDisposable + { + private readonly object _lock = new object(); + private readonly Func _engineFactory; + private OpenTypeFontEngine? _fontEngine; + + public RenderContext(Func engineFactory) + { + if (engineFactory == null) + throw new ArgumentNullException("engineFactory"); + _engineFactory = engineFactory; + } + + public OpenTypeFontEngine FontEngine + { + get + { + if (_fontEngine == null) + { + lock (_lock) + { + if (_fontEngine == null) + _fontEngine = _engineFactory(); + } + } + return _fontEngine; + } + } + + + public void Dispose() + { + if (_fontEngine != null) + { + try { _fontEngine.Dispose(); } catch { /* best effort */ } + _fontEngine = null; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/GradientFill.cs b/src/EPPlus.DrawingRenderer/RenderItems/GradientFill.cs new file mode 100644 index 0000000000..214a5fc828 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/GradientFill.cs @@ -0,0 +1,115 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.ImageRenderer.RenderItems; + +using System.Text; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + /// + /// The path for a gradiant color + /// + public enum ShadePath + { + /// + /// The gradient folows a linear path + /// + Linear, + /// + /// The gradient follows a circular path + /// + Circle, + /// + /// The gradient follows a rectangular path + /// + Rectangle, + /// + /// The gradient follows the shape + /// + Shape + } + public class OffsetRectangle : RenderStyle + { + /// + /// Top offset in percentage + /// + public double TopOffset { get; set; } + /// + /// Bottom offset in percentage + /// + public double BottomOffset { get; set; } + /// + /// Left offset in percentage + /// + public double LeftOffset { get; set; } + /// + /// Right offset in percentage + /// + public double RightOffset { get; set; } + + public override string GetKey() + { + return $"{TopOffset} {BottomOffset} {LeftOffset} {RightOffset}"; + } + } + public class RenderLinearGradientSettings : RenderStyle + { + public double Angle { get; set; } + public bool Scaled { get; set; } + + public override string GetKey() + { + return $"{Angle} {Scaled}"; + } + } + public class RenderGradientFill : RenderStyle + { + public RenderGradientFill() + { + + } + public List Colors { get; set; } = new List(); + public ShadePath ShadePath { get; set; } + public OffsetRectangle FocusPoint { get; set; } = new OffsetRectangle(); + public OffsetRectangle TileRectangle { get; set; } = new OffsetRectangle(); + public RenderLinearGradientSettings LinearSettings { get; private set; } = new RenderLinearGradientSettings(); + /// + /// If the gradient should use the user space as coordinate system or the bounding box of the item. This is only used for gradient fills and is ignored for other fill types. If true, the gradient will use the user space as coordinate system, if false, the gradient will use the bounding box of the item as coordinate system. + /// + public bool UserSpaceOnUse { get; set; } + public override string GetKey() + { + var sb = new StringBuilder(); + foreach(var c in Colors) + { + sb.Append(c.Color.ToArgb()); + sb.Append(' '); + sb.Append(c.Position); + } + sb.Append(ShadePath); + + sb.Append(' '); + + sb.Append(FocusPoint.GetKey()); + sb.Append(' '); + sb.Append(LinearSettings.GetKey()); + + return sb.ToString(); + } + } + + public abstract class RenderStyle + { + public abstract string GetKey(); + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/GradientFillColor.cs b/src/EPPlus.DrawingRenderer/RenderItems/GradientFillColor.cs new file mode 100644 index 0000000000..413f511b71 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/GradientFillColor.cs @@ -0,0 +1,30 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; + +namespace EPPlus.Export.ImageRenderer.RenderItems +{ + public class GradientFillColor + { + public GradientFillColor(double position, Color color) + { + Position = position; + Color = color; + } + + public double Position { get; private set; } + + public Color Color { get; private set; } + public double Opacity { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IBorder.cs b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IBorder.cs new file mode 100644 index 0000000000..4f70d4441a --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IBorder.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Interfaces +{ + public interface IBorder : IFill + { + double? BorderWidth { get; set; } + double[] BorderDashArray { get; set; } + double? BorderDashOffset { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IFill.cs b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IFill.cs new file mode 100644 index 0000000000..f2a1dabed6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IFill.cs @@ -0,0 +1,10 @@ +using EPPlus.DrawingRenderer; +namespace EPPlus.Export.ImageRenderer.RenderItems.Interfaces +{ + public interface IFill + { + string Color { get; set; } + double? Opacity { get; set; } + PathFillMode FillMode { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRectItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRectItem.cs new file mode 100644 index 0000000000..ef091d7641 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRectItem.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Interfaces +{ + internal interface IRectItem + { + double Top { get; set; } + double Left { get; set; } + double Height { get; set; } + double Width { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRender.cs b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRender.cs new file mode 100644 index 0000000000..326c9b37aa --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IRender.cs @@ -0,0 +1,21 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Text; + +namespace EPPlusImageRenderer +{ + internal interface IRender + { + void Render(T renderer); + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IStylingInfoBase.cs b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IStylingInfoBase.cs new file mode 100644 index 0000000000..de110ec790 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Interfaces/IStylingInfoBase.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Interfaces +{ + internal interface IStylingInfoBase + { + string FillColor { get; set; } + string BorderColor { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/PathCommandType.cs b/src/EPPlus.DrawingRenderer/RenderItems/PathCommandType.cs new file mode 100644 index 0000000000..9e3e62a4c2 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/PathCommandType.cs @@ -0,0 +1,27 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlusImageRenderer.RenderItems +{ + public enum PathCommandType : byte + { + Move = 0, + Line = 1, + HorizontalLine = 2, + VerticalLine = 3, + CubicBézier = 4, + QuadraticBézier = 5, + Arc = 6, + End = 0xFF + } + +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/PathCommands.cs b/src/EPPlus.DrawingRenderer/RenderItems/PathCommands.cs new file mode 100644 index 0000000000..224d0de5af --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/PathCommands.cs @@ -0,0 +1,42 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml; +using System; +using System.Globalization; +using System.Text; + +namespace EPPlusImageRenderer +{ + public class PathCommands + { + public PathCommands(PathCommandType type, params double[] coordinates) + { + Type = type; + Coordinates = coordinates; + } + //public SvgRenderItem RenderItem{ get; set;} + public PathCommandType Type { get; } + public double[] Coordinates { get; set; } + public PathCommands Clone() + { + return new PathCommands(Type) + { + Coordinates = (double[])Coordinates.Clone(), + }; + } + } + +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/PresetShapeRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/PresetShapeRenderItem.cs new file mode 100644 index 0000000000..277ab004ab --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/PresetShapeRenderItem.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + //internal class PresetShapeRenderItem : RenderItem + //{ + // internal PresetShapeRenderItem(eShapeStyle style, double top, double left, double width, double height, eTextAutofit autofit) + // { + + // } + // public override RenderItemType Type => RenderItemType.Group; + //} +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/RenderBlipFill.cs b/src/EPPlus.DrawingRenderer/RenderItems/RenderBlipFill.cs new file mode 100644 index 0000000000..5a299f9d4f --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/RenderBlipFill.cs @@ -0,0 +1,130 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; +using System.Security.Cryptography; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + /// + /// Describes how to position two rectangles relative to each other + /// + public enum RectangleAlignment + { + /// + /// Bottom + /// + Bottom, + /// + /// Bottom Left + /// + BottomLeft, + /// + /// Bottom Right + /// + BottomRight, + /// + /// Center + /// + Center, + /// + /// Left + /// + Left, + /// + /// Right + /// + Right, + /// + /// Top + /// + Top, + /// + /// TopLeft + /// + TopLeft, + /// + /// TopRight + /// + TopRight + } + public enum TileFlipMode + { + /// + /// Tiles are not flipped + /// + None, + /// + /// Tiles are flipped horizontally. + /// + X, + /// + /// Tiles are flipped horizontally and Vertically + /// + XY, + /// + /// Tiles are flipped vertically. + /// + Y + } + public class FillTile : RenderStyle + { + /// + /// The direction(s) in which to flip the image. + /// + public TileFlipMode? FlipMode { get; set; } + /// + /// Where to align the first tile with respect to the shape. + /// + public RectangleAlignment? Alignment { get; set; } + /// + /// The ratio for horizontally scale + /// + public double HorizontalRatio { get; set; } + /// + /// The ratio for vertically scale + /// + public double VerticalRatio { get; set; } + /// + /// The horizontal offset after alignment + /// + public double HorizontalOffset { get; set; } + /// + /// The vertical offset after alignment + /// + public double VerticalOffset { get; set; } + + public override string GetKey() + { + return $"{FlipMode} {Alignment} {HorizontalRatio} {VerticalRatio} {HorizontalOffset} {VerticalOffset}"; + } + } + public class RenderBlipFill : RenderStyle + { + internal static SHA256 sha = SHA256.Create(); + public BoundingBox ImageBounds { get; set; } = new BoundingBox(); + public string ContentType { get; set; } + public byte[] ImageBytes { get; set; } + /// + /// The image should be stretched to fill the target. + /// + public bool Stretch { get; set; } = false; + public OffsetRectangle StretchOffset{ get; set; } + public FillTile Tile{ get;set;} + + public override string GetKey() + { + var imageHash = Convert.ToBase64String(sha.ComputeHash(ImageBytes)); + return $"{ContentType} {imageHash} {Stretch} {StretchOffset.GetKey()} {Tile.GetKey()}"; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs new file mode 100644 index 0000000000..bd46e6b0c0 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs @@ -0,0 +1,425 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System.Drawing; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + public enum FillType + { + SolidFill, + GradientFill, + PatternFill + } + /// + /// The compound line type. Used for underlining text + /// + public enum CompoundLineStyle + { + /// + /// Double lines with equal width + /// + Double, + /// + /// Single line normal width + /// + Single, + /// + /// Double lines, one thick, one thin + /// + DoubleThickThin, + /// + /// Double lines, one thin, one thick + /// + DoubleThinThick, + /// + /// Three lines, thin, thick, thin + /// + TripleThinThickThin + } + public enum LineCap + { + /// + /// A flat line cap + /// + Flat, //flat + /// + /// A round line cap + /// + Round, + /// + /// A Square line cap + /// + Square + } + + public enum LineJoin + { + Arcs, + Bevel, + Miter, + MiterClip, + Round + } + public class UseReferenceRenderItem : RenderItem + { + public UseReferenceRenderItem(BoundingBox parent, string hRef) : base(parent) + { + Href = hRef; + } + public string Href { get; private set; } + + public override RenderItemType Type => RenderItemType.UseReference; + + public double X + { + get + { + return Bounds.Left; + } + set + { + Bounds.Left = value; + } + } + public double Y + { + get + { + return Bounds.Top; + } + set + { + Bounds.Top = value; + } + } + } + public class RectRenderItem : RenderItem + { + public RectRenderItem(BoundingBox parent) : base(parent) + { + + } + public override RenderItemType Type => RenderItemType.Rect; + public double Left { get { return Bounds.Left; } set { Bounds.Left = value; } } + public double Top { get { return Bounds.Top; } set { Bounds.Top = value; } } + public double Width { get { return Bounds.Width; } set { Bounds.Width = value; } } + public double Height { get { return Bounds.Height; } set { Bounds.Height = value; } } + public double Right { get { return Bounds.Left + Width; } } + public double Bottom { get { return Bounds.Top + Height; } } + public double GlobalLeft => Bounds.GlobalLeft; + public double GlobalTop => Bounds.GlobalTop; + public double GlobalRight => Bounds.GlobalLeft + Width; + public double GlobalBottom => Bounds.GlobalTop + Height; + } + public class GroupRenderItem : RenderItem + { + public GroupRenderItem(BoundingBox parent) : base(parent) + { + } + public GroupRenderItem(BoundingBox parent, double rotation) : base(parent) + { + Rotation = rotation; + } + + public GroupRenderItem() : base() + { + Bounds.Parent = TranslationOffset; + } + + public GroupRenderItem(double localXPos, double localYPos) : this() + { + TranslationOffset = new Graphics.Point(localXPos, localYPos); + } + + + public GroupRenderItem(BoundingBox parent, double rotation, Transform rotationPoint = null) : this(0, 0) + { + TranslationOffset.Parent = parent; + Rotation = rotation; + if (rotationPoint != null) + { + RotationPoint = new Graphics.Point(rotationPoint.LocalPosition.X, rotationPoint.LocalPosition.Y); + } + } + /// + /// The top position of the group. This is the position of the group relative to its parent. The child items are positioned relative to this position. + /// + public double Top { get { return Bounds.Top; } set { Bounds.Top = value; } } + /// + /// The left position of the group. This is the position of the group relative to its parent. The child items are positioned relative to this position. + /// + public double Left { get { return Bounds.Left; } set { Bounds.Left = value; } } + public override RenderItemType Type => RenderItemType.Group; + public string TextAnchor { get; set; } + public double Rotation { get; set; } + public string GroupTransform = ""; + public List RenderItems { get; } = new List(); + + Graphics.Point _altRotationPoint = null; + /// + /// The translated position of this item in points + /// Also the parent position of the group item + /// (This may seem strange but it ensures the the translation is seen + /// immediately in the global position of GroupItem without affecting local position) + /// + public Graphics.Point TranslationOffset = new Graphics.Point(0, 0); + public Graphics.Point RotationPoint + { + get + { + if (_altRotationPoint == null) + { + return TranslationOffset; + } + return _altRotationPoint; + } + set + { + _altRotationPoint = value; + } + } + + public Coordinate Scale = null; + + internal void SetRotationPointToCenterOfGroup(double rotation = double.NaN) + { + RotationPoint = new Graphics.Point(Bounds.Width / 2, Bounds.Height / 2); + + if (double.IsNaN(rotation) == false) + { + Rotation = rotation; + } + } + + public void AddChildItem(RenderItem item) + { + item.Bounds.Parent = TranslationOffset; + RenderItems.Add(item); + + Bounds.Width = item.Bounds.Right > Bounds.Width ? item.Bounds.Right : Bounds.Width; + Bounds.Height = item.Bounds.Bottom > Bounds.Height ? item.Bounds.Bottom : Bounds.Height; + } + } + public class PathRenderItem : RenderItem + { + public override RenderItemType Type => RenderItemType.Path; + public PathRenderItem(BoundingBox parent) : base(parent) + { + + } + public List Commands { get; } = new List(); + } + public class EllipseRenderItem : RenderItem + { + public EllipseRenderItem(BoundingBox parent) : base(parent) + { + + } + public override RenderItemType Type => RenderItemType.Ellipse; + public double Cx { get; set; } + public double Cy { get; set; } + public double Rx { get; set; } + public double Ry { get; set; } + } + public class LineRenderItem : RenderItem + { + public LineRenderItem(BoundingBox parent) : base(parent) + { + + } + double _x1, _y1, _x2, _y2; + public double X1 + { + get + { + return _x1; + } + set + { + _x1 = value; + UpdateBounds(); + } + } + public double Y1 + { + get + { + return _y1; + } + set + { + _y1 = value; + UpdateBounds(); + } + } + public double X2 + { + get + { + return _x2; + } + set + { + _x2 = value; + UpdateBounds(); + } + } + public double Y2 + { + get + { + return _y2; + } + set + { + _y2 = value; + UpdateBounds(); + } + } + private void UpdateBounds() + { + var px = Math.Min(X1, X2); + var py = Math.Min(Y1, Y2); + var sizeX = Math.Abs(X2 - X1); + var sizeY = Math.Abs(Y2 - Y1); + + Bounds.Position = new Vector2(px, py); + Bounds.Size = new Vector2(sizeX, sizeY); + } + public LineRenderItem Clone() + { + var clone = new LineRenderItem((BoundingBox)Bounds.Parent); + CloneBase(clone); + clone._x1 = X1; + clone._y1 = Y1; + clone._x2 = X2; + clone._y2 = Y2; + clone.UpdateBounds(); + return clone; + } + public override RenderItemType Type => RenderItemType.Line; + } + public abstract class DrawingObject + { + public virtual void AppendRenderItems(List renderItems) { } + } + public abstract class RenderItem : RenderItemBase + { + protected RenderItem() + { + } + protected RenderItem(BoundingBox parent) + { + Bounds.Parent = parent; + } + //internal abstract void GetBounds(out double il, out double it, out double ir, out double ib); + public virtual void GetBounds(out double il, out double it, out double ir, out double ib) + { + il = Bounds.Left; + it = Bounds.Top; + ir = Bounds.Right; + ib = Bounds.Bottom; + } + public string DefId { get; set; } + //internal bool IsEndOfGroup { get; set; } = false; + public string FillColor { get; set; } + public string FilterName { get; set; } + public RenderGradientFill GradientFill { get; set; } + public FillType FillType { get; set; } + public double? FillOpacity { get; set; } + public string BorderColor { get; set; } + public RenderGradientFill BorderGradientFill { get; set; } + public RenderPatternFill PatternFill { get; set; } + public RenderBlipFill BlipFill { get; set; } + public double? BorderWidth { get; set; } + public double[] BorderDashArray { get; set; } + public int? StrokeMiterLimit { get; set; } + public CompoundLineStyle CompoundLineStyle { get; set; } = CompoundLineStyle.Single; + public double? BorderDashOffset { get; set; } + public LineCap LineCap { get; set; } = LineCap.Flat; + public LineJoin LineJoin { get; set; } = LineJoin.Miter; + public double? BorderOpacity { get; set; } + public PathFillMode FillColorSource { get; set; } = PathFillMode.Norm; + public PathFillMode BorderColorSource { get; set; } = PathFillMode.Norm; + public double? GlowRadius { get; set; } + public string GlowColor { get; set; } + public RenderShadowEffect OuterShadowEffect { get; set; } + + /// + /// The origin point for any transform actions in svg. + /// Normally/Default 0,0 + /// + public Coordinate TransformOrigin { get; set; } = null; + + protected void CloneBase(RenderItem item) + { + item.FillColor = FillColor; + item.FillOpacity = FillOpacity; + item.BorderWidth = BorderWidth; + item.BorderColor = BorderColor; + item.BorderDashArray = BorderDashArray; + item.BorderDashOffset = BorderDashOffset; + item.BorderOpacity = BorderOpacity; + item.LineJoin = LineJoin; + item.LineCap = LineCap; + item.FillColorSource = FillColorSource; + } + internal void GetOuterShadowColor(out string shadowColor, out double opacity) + { + if (OuterShadowEffect == null) + { + shadowColor = null; + opacity = 0; + + } + else + { + var tc = OuterShadowEffect.OuterShadowEffectColor; + if (tc.A < 255 && tc != Color.Empty) + { + opacity = tc.A / 255D; + } + else + { + opacity = 1; + } + shadowColor = "#" + tc.ToArgb().ToString("x8").Substring(2); + } + } + + internal string GetFilterKey() + { + return $"{GlowColor} {GlowRadius} { OuterShadowEffect?.GetKey()}"; + } + } + /// + /// Base class for any item rendered. + /// + public abstract class RenderItemBase + { + public BoundingBox Bounds = new BoundingBox(); + public abstract RenderItemType Type { get; } + public virtual void GetBounds(out double il, out double it, out double ir, out double ib) + { + il = Bounds.Left; + it = Bounds.Top; + ir = Bounds.Right; + ib = Bounds.Bottom; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/RenderPatternFill.cs b/src/EPPlus.DrawingRenderer/RenderItems/RenderPatternFill.cs new file mode 100644 index 0000000000..57b9dd2755 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/RenderPatternFill.cs @@ -0,0 +1,250 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using System.Drawing; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + /// + /// Pattern styles for drawing fills + /// + public enum FillPatternStyle + { + /// + /// 5 Percent + /// + Pct5, + /// + /// 10 Percent + /// + Pct10, + /// + /// 20 Percent + /// + Pct20, + /// + /// 25 Percent + /// + Pct25, + /// + /// 30 Percent + /// + Pct30, + /// + /// 40 Percent + /// + Pct40, + /// + /// 50 Percent + /// + Pct50, + /// + /// 60 Percent + /// + Pct60, + /// + /// 70 Percent + /// + Pct70, + /// + /// 75 Percent + /// + Pct75, + /// + /// 80 Percent + /// + Pct80, + /// + /// 90 Percent + /// + Pct90, + /// + /// Horizontal + /// + Horz, + /// + /// Vertical + /// + Vert, + /// + /// Light Horizontal + /// + LtHorz, + /// + /// Light Vertical + /// + LtVert, + /// + /// Dark Horizontal + /// + DkHorz, + /// + /// Dark Vertical + /// + DkVert, + /// + /// Narrow Horizontal + /// + NarHorz, + /// + /// Narrow Vertical + /// + NarVert, + /// + /// Dashed Horizontal + /// + DashHorz, + /// + /// Dashed Vertical + /// + DashVert, + /// + /// Cross + /// + Cross, + /// + /// Downward Diagonal + /// + DnDiag, + /// + /// Upward Diagonal + /// + UpDiag, + /// + /// Light Downward Diagonal + /// + LtDnDiag, + /// + /// Light Upward Diagonal + /// + LtUpDiag, + /// + /// Dark Downward Diagonal + /// + DkDnDiag, + /// + /// Dark Upward Diagonal + /// + DkUpDiag, + /// + /// Wide Downward Diagonal + /// + WdDnDiag, + /// + /// Wide Upward Diagonal + /// + WdUpDiag, + /// + /// Dashed Downward Diagonal + /// + DashDnDiag, + /// + /// Dashed Upward DIagonal + /// + DashUpDiag, + /// + /// Diagonal Cross + /// + DiagCross, + /// + /// Small Checker Board + /// + SmCheck, + /// + /// Large Checker Board + /// + LgCheck, + /// + /// Small Grid + /// + SmGrid, + /// + /// Large Grid + /// + LgGrid, + /// + /// Dotted Grid + /// + DotGrid, + /// + /// Small Confetti + /// + SmConfetti, + /// + /// Large Confetti + /// + LgConfetti, + /// + /// Horizontal Brick + /// + HorzBrick, + /// + /// Diagonal Brick + /// + DiagBrick, + /// + /// Solid Diamond + /// + SolidDmnd, + /// + /// Open Diamond + /// + OpenDmnd, + /// + /// Dotted Diamond + /// + DotDmnd, + /// + /// Plaid + /// + Plaid, + /// + /// Sphere + /// + Sphere, + /// + /// Weave + /// + Weave, + /// + /// Divot + /// + Divot, + /// + /// Shingle + /// + Shingle, + /// + /// Wave + /// + Wave, + /// + /// Trellis + /// + Trellis, + /// + /// Zig Zag + /// + ZigZag + } +} +public class RenderPatternFill : RenderStyle +{ + public FillPatternStyle PatternType { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public override string GetKey() + { + return $"{PatternType}|{ForegroundColor.ToArgb()} {BackgroundColor.ToArgb()}"; + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/RenderShadowEffect.cs b/src/EPPlus.DrawingRenderer/RenderItems/RenderShadowEffect.cs new file mode 100644 index 0000000000..b21b8b2c15 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/RenderShadowEffect.cs @@ -0,0 +1,29 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + public class RenderShadowEffect : RenderStyle + { + public Color OuterShadowEffectColor { get; set; } + public double Distance { get; set; } + public double? BlurRadius { get; set; } + public double? Direction { get; set; } + + public override string GetKey() + { + return $"{OuterShadowEffectColor.ToArgb()} {Distance} {BlurRadius} {Direction}"; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/GroupItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/GroupItem.cs new file mode 100644 index 0000000000..1c86273a2b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/GroupItem.cs @@ -0,0 +1,102 @@ +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System.Collections.Generic; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal abstract class GroupItem : RenderItem + { + /// + /// In degrees + /// + internal double Rotation = double.NaN; + /// + /// The translated position of this item in points + /// Also the parent position of the group item + /// (This may seem strange but it ensures the the translation is seen + /// immediately in the global position of GroupRenderItemBaseNew without affecting local position) + /// + internal Point TranslationOffset = new Point(0,0); + + Point _altRotationPoint = null; + + internal Point RotationPoint + { + get + { + if (_altRotationPoint == null) + { + return TranslationOffset; + } + return _altRotationPoint; + } + set + { + _altRotationPoint = value; + } + } + + internal Coordinate Scale = null; + + + //Transform _rotationPoint; + + /// + /// Items contained in this group + /// + internal protected List _childItems = new List(); + + public GroupItem(DrawingRenderer renderer) : base(renderer) + { + Bounds.Parent = TranslationOffset; + //_rotationPoint = Bounds; + } + + public GroupItem(DrawingRenderer renderer, double localXPos, double localYPos) : this(renderer) + { + Bounds.Left = localXPos; + Bounds.Top = localYPos; + } + + + public GroupItem(DrawingBase renderer, BoundingBox parent, double rotation, Transform rotationPoint = null) : this(renderer, 0, 0) + { + TranslationOffset.Parent = parent; + Rotation = rotation; + if (rotationPoint != null) + { + RotationPoint = new Point(rotationPoint.LocalPosition.X, rotationPoint.LocalPosition.Y); + } + } + + internal void SetRotationPointToCenterOfGroup(double rotation = double.NaN) + { + RotationPoint = new Point(Bounds.Width/2, Bounds.Height/2); + + if (double.IsNaN(rotation) == false) + { + Rotation = rotation; + } + } + + internal void AddChildItem(RenderItem item) + { + if (item is GroupItem) + { + var subGroup = (GroupItem)item; + subGroup.TranslationOffset.Parent = Bounds; + } + else + { + item.Bounds.Parent = Bounds; + } + _childItems.Add(item); + + Bounds.Width = item.Bounds.Right > Bounds.Width ? item.Bounds.Right : Bounds.Width; + Bounds.Height = item.Bounds.Bottom > Bounds.Height ? item.Bounds.Bottom : Bounds.Height; + } + + public override RenderItemType Type => RenderItemType.Group; + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/InnerGroup.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/InnerGroup.cs new file mode 100644 index 0000000000..ea31127a57 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/InnerGroup.cs @@ -0,0 +1,31 @@ +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System.Collections.Generic; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal abstract class InnerGroup : RenderItem + { + /// + /// Items contained in this group + /// + internal protected List _childItems = new List(); + + public InnerGroup(DrawingRenderer renderer) : base(renderer) + { + } + + internal void AddChildItem(RenderItem item) + { + item.Bounds.Parent = Bounds; + + _childItems.Add(item); + + Bounds.Width = item.Bounds.Right > Bounds.Width ? item.Bounds.Right : Bounds.Width; + Bounds.Height = item.Bounds.Bottom > Bounds.Height ? item.Bounds.Bottom : Bounds.Height; + } + + public override RenderItemType Type => RenderItemType.Group; + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/ParagraphItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/ParagraphItem.cs new file mode 100644 index 0000000000..a932176a67 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/ParagraphItem.cs @@ -0,0 +1,581 @@ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + public enum DrawingTextLineSpacing + { + /// + /// Single line spacing + /// + Single, + /// + /// 1.5 lines + /// + OneAndAHalf, + /// + /// Double line spacing + /// + Double, + /// + /// Exact point spacing + /// + Exactly, + /// + /// Multiple line spacing + /// + Multiple + } + /// + /// Text alignment + /// + public enum TextAlignment + { + /// + /// Left alignment + /// + Left, + /// + /// Center alignment + /// + Center, + /// + /// Right alignment + /// + Right, + /// + /// Distributes the text words across an entire text line + /// + Distributed, + /// + /// Align text so that it is justified across the whole line. + /// + Justified, + /// + /// Aligns the text with an adjusted kashida length for Arabic text + /// + JustifiedLow, + /// + /// Distributes Thai text specially, specially, because each character is treated as a word + /// + ThaiDistributed + } + + internal abstract class ParagraphItem : RenderItem + { + TextLayoutEngine _layout; + + double _leftMargin; + double _rightMargin; + + DrawingTextLineSpacing _lsType; + double _lineSpacingAscendantOnly; + double? _lsMultiplier = null; + internal bool IsFirstParagraph { get; private set; } + List _paragraphLines = new List(); + protected List _textRunDisplayText = new List(); + + List _newTextFragments; + int _manualFragmentsStartIndex = -1; + List _manualFragments; + internal protected MeasurementFont _paragraphFont; + internal TextBodyItem ParentTextBody { get; set; } + internal double ParagraphLineSpacing { get; private set; } + internal TextAlignment HorizontalAlignment { get; private set; } + internal List Runs { get; set; } = new List(); + + internal bool DisplayBounds { get; set; } = false; + + private List _lines; + + //Start temp workaround vars + string _textIfEmpty = null; + ExcelDrawingParagraph _p = null; + //end temp workaround vars + + private double? _centerAdjustment = null; + + internal List SpaceWidthsPerLine = new List(); + + bool LinespacingIsExact + { + get + { + return _lsMultiplier.HasValue == false; + } + } + + public ParagraphItem(TextBodyItem textBody, DrawingBase renderer, BoundingBox parent) : base(renderer, parent) + { + ParentTextBody = textBody; + Bounds.Name = "Paragraph"; + var defaultFont = new MeasurementFont { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Regular }; + _paragraphFont = defaultFont; + + _layout = OpenTypeFonts.GetTextLayoutEngineForFont(defaultFont); + ParagraphLineSpacing = GetParagraphLineSpacingInPoints(100, (TextShaper)OpenTypeFonts.GetShaperForFont(defaultFont), defaultFont.Size); + } + + public ParagraphItem(TextBodyItem textBody, DrawingBase renderer, BoundingBox parent, ExcelDrawingParagraph p, string textIfEmpty = null) : base(renderer, parent) + { + ParentTextBody = textBody; + IsFirstParagraph = p == p._paragraphs[0]; + + if (p.DefaultRunProperties.Fill != null && p.DefaultRunProperties.Fill.IsEmpty == false) + { + if (IsFirstParagraph) + { + if (p.DefaultRunProperties.Fill != null) + { + SetDrawingPropertiesFill(p.DefaultRunProperties.Fill, null); + } + } + else + { + //Drawingproperties has fallback to firstDefault but excel does not display it so we should not either. + if (p.DefaultRunProperties != p._paragraphs.FirstDefaultRunProperties) + { + SetDrawingPropertiesFill(p.DefaultRunProperties.Fill, null); + } + else + { + var fc = EPPlusColorConverter.GetThemeColor(DrawingRenderer.Theme.ColorScheme.Light1); + fc = ColorUtils.GetAdjustedColor(PathFillMode.Norm, fc); + FillColor = "#" + fc.ToArgb().ToString("x8").Substring(2); + //Use shape fill somehow + //Maybe use a name property for fallback theme accent1 color? + } + } + } + else + { + if (p._paragraphs.FirstDefaultRunProperties != null && p._paragraphs.FirstDefaultRunProperties.Fill != null && p._paragraphs.FirstDefaultRunProperties.Fill.IsEmpty == false) + { + var fill = p._paragraphs.FirstDefaultRunProperties.Fill; + SetDrawingPropertiesFill(fill, null); + } + } + + //---Initialize Bounds / Margins-- - + Bounds.Name = "Paragraph"; + + var indent = 48 * p.IndentLevel; + _leftMargin = p.LeftMargin + p.Indent + indent; + _rightMargin = p.RightMargin; + + _leftMargin = _leftMargin.PixelToPoint(); + _rightMargin = _rightMargin.PixelToPoint(); + + HorizontalAlignment = p.HorizontalAlignment; + _leftMargin = _leftMargin.PixelToPoint(); + _rightMargin = _rightMargin.PixelToPoint(); + + HorizontalAlignment = p.HorizontalAlignment; + + if (ParentTextBody.AutoSize == false) + { + Bounds.Left = 0; + Bounds.Width = ParentTextBody.MaxWidth; + + //Left is equal to left Paragraph margin + //Textbody or Textbox are assumed to handle shape/chart margins + //Paragraph handles only indentations/margins that is applied ON TOP of those margins + //Paragraph left is the exact position where the text itself starts on the left + if (HorizontalAlignment != TextAlignment.Center) + { + Bounds.Left = GetAlignmentHorizontal(HorizontalAlignment); + } + else + { + //Center is a bit strange the bounds really are the same as left or right aligned + //It doesn't truly matter as only left min and right max play a role + Bounds.Left = GetAlignmentHorizontal(TextAlignment.Left); + _centerAdjustment = GetAlignmentHorizontal(HorizontalAlignment); + + } + Bounds.Width = parent.Width - _rightMargin - _leftMargin; + } + + //---Initialize / calculate lines and runs--- + //measurer must be set before AddLinesAndRichText + _paragraphFont = p.DefaultRunProperties.GetMeasureFont(); + + //---Get measurer--- + _layout = OpenTypeFonts.GetTextLayoutEngineForFont(_paragraphFont); + + //---Calculate linespacing--- + int numLines = _paragraphLines.Count; + _lsType = p.LineSpacing.LineSpacingType; + ParagraphLineSpacing = GetParagraphLineSpacingInPoints(p.LineSpacing.Value, + (TextShaper) OpenTypeFonts.GetShaperForFont(_paragraphFont), + _paragraphFont.Size); + + + ImportLinesAndTextRuns(p, textIfEmpty); + } + + private double GetParagraphLineSpacingInPoints(double spacingValue, TextShaper fmExact, float fontSize) + { + if (_lsType == DrawingTextLineSpacing.Exactly) + { + if (IsFirstParagraph) + { + _lineSpacingAscendantOnly = spacingValue; + } + return spacingValue; + } + else + { + var multiplier = (spacingValue / 100); + _lsMultiplier = multiplier; + if (IsFirstParagraph) + { + _lineSpacingAscendantOnly = multiplier * fmExact.GetAscentInPoints(fontSize); + } + return multiplier * fmExact.GetLineHeightInPoints(fontSize); + } + } + + //public void AddOwnText(string text) + //{ + // var fragment = new TextFragment(); + // fragment.Text = text; + // fragment.Font = ParagraphFont; + // _manualFragments.Add(fragment); + + // //if(_newTextFragments == null) + // //{ + // // //This should probably never happen + // // throw new InvalidOperationException("Must GENERATE textfragments first in the constructor"); + // // //GenerateTextFragments(text); + // //} + // //else + // //{ + // // var fragment = new TextFragment(); + // // fragment.Text = text; + // // fragment.Font = ParagraphFont; + // // //_newTextFragments.Add(fragment); + // // _manualFragments.Add(fragment); + // //} + + // //Redo whole thing for now. + // //Import and wrapping really should be completely seperated but can't refactor all of it yet + // //AddTextLinesAndSpacing(_p, _textIfEmpty); + //} + + public void AddOwnText(TextFragment fragment) + { + //_manualFragments.Add(fragment); + + if (_newTextFragments == null) + { + //This should probably never happen + throw new InvalidOperationException("Must GENERATE textfragments first in the constructor"); + //GenerateTextFragments(text); + } + else + { + if(_manualFragmentsStartIndex == -1) + { + _manualFragmentsStartIndex = _newTextFragments.Count; + } + //_newTextFragments.Add(fragment); + _newTextFragments.Add(fragment); + } + + + //Redo whole thing for now. + //Import and wrapping really should be completely seperated but can't refactor all of it yet + AddTextLinesAndSpacing(_p, _textIfEmpty); + } + + + internal protected TextRunItem AddRenderItemTextRun(ExcelParagraphTextRunBase origTxtRun, string displayText) + { + var targetTxtRun = CreateTextRun(origTxtRun, Bounds, displayText); + + Runs.Add(targetTxtRun); + return targetTxtRun; + } + + private void AddText(string text, MeasurementFont font) + { + var container = CreateTextRun(font, Bounds, text); + Runs.Add(container); + + container.Bounds.Name = $"Container{Runs.Count}"; + } + + private void AddText(string text, ExcelTextFont font) + { + var mf = font.GetMeasureFont(); + var measurer = OpenTypeFonts.GetTextLayoutEngineForFont(mf); + + var container = CreateTextRun(text, font, Bounds, text); + Runs.Add(container); + //Bounds.Width = container.Bounds.Width + 0.001; //TODO: fix for equal width issue + container.Bounds.Name = $"Container{Runs.Count}"; + } + + void GenerateTextFragments(string text) + { + _newTextFragments = new List(); + + if (string.IsNullOrEmpty(text) == false) + { + var currentFrag = new TextFragment() { Text = text, Font = _paragraphFont}; + _newTextFragments.Add(currentFrag); + } + } + + /// + /// Log linebreak positions and sizes of the runs + /// So that we can easily know what textfragment is on what line and what size it has later + /// + /// + void GenerateTextFragments(ExcelDrawingTextRunCollection runs/*, string textIfEmpty*/) + { + List runContents = new List(); + List fonts = new List(); + + for (int i = 0; i < runs.Count(); i++) + { + var txtRun = runs[i]; + var runFont = txtRun.GetMeasurementFont(); + + fonts.Add(runFont); + runContents.Add(txtRun.Text); + } + + _newTextFragments = new List(); + + for (int i = 0; i < runContents.Count(); i++) + { + if (string.IsNullOrEmpty(runContents[i]) == false) + { + var currentFrag = new TextFragment() { Text = runContents[i], Font = fonts[i] }; + _newTextFragments.Add(currentFrag); + } + } + } + + internal void ImportLinesAndTextRunsDefault(string textIfEmpty) + { + GenerateTextFragments(textIfEmpty); + + if (HorizontalAlignment != TextAlignment.Center) + { + Bounds.Left = GetAlignmentHorizontal(HorizontalAlignment); + } + else + { + Bounds.Left = GetAlignmentHorizontal(TextAlignment.Left); + _centerAdjustment = GetAlignmentHorizontal(HorizontalAlignment); + } + + AddTextLinesAndSpacing(null, textIfEmpty); + } + private void ImportLinesAndTextRuns(ExcelDrawingParagraph p, string textIfEmpty) + { + if (p.TextRuns.Count == 0 && string.IsNullOrEmpty(textIfEmpty) == false) + { + ImportLinesAndTextRunsDefault(textIfEmpty); + } + else + { + //Log line positions and run sizes + GenerateTextFragments(p.TextRuns); + AddTextLinesAndSpacing(p, textIfEmpty); + } + } + + private void AddTextLinesAndSpacing(ExcelDrawingParagraph p, string textIfEmpty) + { + //Temp workaround + if (_p == null) + { + _p = p; + } + if (_textIfEmpty == null) + { + _textIfEmpty = textIfEmpty; + } + + _lines = WrapFragmentsToLines(); + + //In points + double lastDescent = 0; + double lineTop = 0; + double greatestWidth = 0; + + if (_lines != null && _lines.Count != 0) + { + //This could be moved into a textLines collection class + //START + var idxOfLargestLine = 0; + double widthOfLargestLine = _lines[0].GetWidthWithoutTrailingSpaces(); + + for (int i = 1; i < _lines.Count; i++) + { + if (_lines[i].Width > widthOfLargestLine) + { + var ctrLineWidth = _lines[i].GetWidthWithoutTrailingSpaces(); + SpaceWidthsPerLine.Add(_lines[i].lastFontSpaceWidth); + widthOfLargestLine = ctrLineWidth; + idxOfLargestLine = i; + } + } + //END + + + if (HorizontalAlignment == TextAlignment.Center && ParentTextBody.AutoSize && _centerAdjustment != null && string.IsNullOrEmpty(textIfEmpty)) + { + //Bounds of the paragraph should be bounds of the text itself. + //Therefore we must know the starting point to set accurate left and offset from left. + Bounds.Left = _centerAdjustment.Value - (widthOfLargestLine / 2); + } + else + { + Bounds.Left = 0; + } + //if (ParentTextBody.AutoSize) + //{ + // //Bounds of the paragraph should be bounds of the text itself. + // //Therefore we must know the starting point to set accurate left and offset from left. + // Bounds.Left = 0; + //} + + foreach (var line in _lines) + { + double prevWidth = 0; + + if (HorizontalAlignment == TextAlignment.Center) + { + var ctrLineWidth = line.GetWidthWithoutTrailingSpaces(); + //Calculate difference in widths and split to get offset between leftmost position and current line + prevWidth = (widthOfLargestLine - ctrLineWidth) / 2; + } + else if (HorizontalAlignment == TextAlignment.Right) + { + //Note that the actual bounds with the space will be outside max bounds. + //This appears to be how excel does it + var ctrLineWidth = line.GetWidthWithoutTrailingSpaces(); + prevWidth = widthOfLargestLine - ctrLineWidth; + } + + if (LinespacingIsExact == false) + { + lineTop += line.LargestAscent + lastDescent; + } + else + { + lineTop += ParagraphLineSpacing; + } + if (line.GetWidthWithoutTrailingSpaces() > greatestWidth) + { + greatestWidth = line.GetWidthWithoutTrailingSpaces(); + } + + foreach (var lineFragment in line.LineFragments) + { + var displayText = lineFragment.Text; + + + if (p != null && p.TextRuns.Count == 0 && string.IsNullOrEmpty(textIfEmpty) == false) + { + //Import fallback text with paragraph settings + AddText(displayText, p.DefaultRunProperties); + } + else if (p != null && p.TextRuns.Count != 0) + { + var rtIdx = _newTextFragments.IndexOf(lineFragment.OriginalTextFragment); + if (rtIdx > p.TextRuns.Count - 1) + { + AddText(displayText, _newTextFragments[rtIdx].Font); + } + else + { + //Import Paragraph text run + var idx = _newTextFragments.IndexOf(lineFragment.OriginalTextFragment); + AddRenderItemTextRun(p.TextRuns[idx], displayText); + } + } + else + { + //Import fallback with default settings from constructor + AddText(displayText, _paragraphFont); + } + TextRunItem runItem = Runs.Last(); + runItem.Bounds.Left = prevWidth; + runItem.YPosition = lineTop; + + runItem.Bounds.Width = lineFragment.Width; + prevWidth += lineFragment.Width; + } + lastDescent = line.LargestDescent; + } + } + Bounds.Height = lineTop + lastDescent; + Bounds.Width = greatestWidth; + } + + List WrapFragmentsToLines(List fragments = null) + { + if(fragments == null ) + { + fragments = _newTextFragments; + } + + if (fragments.Count > 0) + { + if(_layout == null) + { + _layout = OpenTypeFonts.GetTextLayoutEngineForFont((fragments[0].Font)); + } + + var maxWidthPoints = Math.Round(ParentTextBody.MaxWidth, 0, MidpointRounding.AwayFromZero); + + _lines = _layout.WrapRichTextLines(fragments, maxWidthPoints); + return _lines; + } + return new List(); + } + + internal double GetAlignmentHorizontal(TextAlignment txAlignment) + { + var area = Bounds; + double x = 0; + switch (txAlignment) + { + case TextAlignment.Left: + default: + x = area.Left + _leftMargin; + break; + case TextAlignment.Center: + x = (area.Right / 2) + _leftMargin - _rightMargin; + break; + case TextAlignment.Right: + x = area.Right - _rightMargin; + break; + } + + return x; + } + + /// + /// Type of textrun defined by child type + /// + /// + /// + /// + /// + internal abstract TextRunItem CreateTextRun(ExcelParagraphTextRunBase run, BoundingBox parent, string displayText); + internal abstract TextRunItem CreateTextRun(string text, ExcelTextFont font, BoundingBox parent, string displayText); + internal abstract TextRunItem CreateTextRun(MeasurementFont font, BoundingBox parent, string displayText); + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextBodyItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextBodyItem.cs new file mode 100644 index 0000000000..eb91d8feba --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextBodyItem.cs @@ -0,0 +1,274 @@ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace EPPlus.DrawingRenderer.RenderItems +{ + /// + /// Margin left = X + /// Margin right = Y + /// + internal abstract class TextBodyItem : DrawingObject + { + public TextBodyItem(DrawingBase renderer, BoundingBox parent, bool autoSize) : base(renderer, parent) + { + Bounds.Name = "TxtBody"; + Bounds.Parent = parent; + AutoSize = autoSize; + } + public TextBodyItem(DrawingBase renderer, BoundingBox parent, double maxWidth, double maxHeight) : base(renderer, parent) + { + Bounds.Name = "TxtBody"; + Bounds.Parent = parent; + MaxWidth = maxWidth; + MaxHeight = maxHeight; + AutoSize = false; + } + internal bool AutoSize { get; set; } + internal double MaxWidth { get; set; } + internal double MaxHeight { get; set; } + + /// + /// Shorthand for Bounds.Width + /// + internal double Width { get { return Bounds.Width; } set { Bounds.Width = value; } } + + /// + /// Shorthand for Bounds.Height + /// + internal double Height { get { return Bounds.Height; } set { Bounds.Height = value; } } + + internal string FontColorString { get; set; } + + internal eTextAnchoringType VerticalAlignment = eTextAnchoringType.Top; + + internal abstract List Paragraphs { get; set; } + + public bool AllowOverflow; + + internal bool WrapText = true; + + internal string _text; + + public void ImportParagraph(ExcelDrawingParagraph item, double startingY, string text=null) + { + var measureFont = item.DefaultRunProperties.GetMeasureFont(); + bool isFirst = Paragraphs.Count == 0; + + var paragraph = CreateParagraph(this, item, Bounds, text); + paragraph.Bounds.Name = $"Container{Paragraphs.Count}"; + paragraph.Bounds.Top = startingY; + _text = text; + + if(AutoSize) + { + if (Paragraphs.Count == 0) + { + Bounds.Height = paragraph.Bounds.Height; + } + else + { + Bounds.Height += paragraph.Bounds.Height; + } + + if (Bounds.Width < paragraph.Bounds.Width || (Bounds.Width == MaxWidth && Paragraphs.Count == 0)) + { + Bounds.Width = paragraph.Bounds.Width; + } + } + Paragraphs.Add(paragraph); + } + + public void AddParagraph(double startingY, string text = null) + { + var paragraph = CreateParagraph(this, Bounds, text); + paragraph.Bounds.Name = $"Container{Paragraphs.Count}"; + paragraph.Bounds.Top = startingY; + _text = text; + + if (AutoSize) + { + if (Paragraphs.Count == 0) + { + Bounds.Height = paragraph.Bounds.Height; + } + else + { + Bounds.Height += paragraph.Bounds.Height; + } + + if (Bounds.Width < paragraph.Bounds.Width || (Bounds.Width == MaxWidth && Paragraphs.Count == 0)) + { + Bounds.Width = paragraph.Bounds.Width; + } + } + Paragraphs.Add(paragraph); + } + + internal void SetHorizontalAlignmentPosition() + { + //if (AutoSize) + //{ + foreach (var p in Paragraphs) + { + switch (p.HorizontalAlignment) + { + case TextAlignment.Left: + p.Bounds.Left = 0; + break; + case TextAlignment.Center: + p.Bounds.Left = (Bounds.Width / 2) - (p.Bounds.Width / 2); + break; + case TextAlignment.Right: + p.Bounds.Left = Bounds.Right - p.Bounds.Width; + break; + case TextAlignment.Distributed: + case TextAlignment.Justified: + case TextAlignment.JustifiedLow: + case TextAlignment.ThaiDistributed: + p.Bounds.Left = 0; //TODO: Set left for now as we do not support distributed spacing yet + break; + } + } + //} + } + + internal virtual void ImportTextBody(ExcelTextBody body, ExcelHorizontalAlignment horizontalDefault = ExcelHorizontalAlignment.Left) + { + _text = null; + VerticalAlignment = body.Anchor; + + //We already apply bounds top via the parent Transform + double currentHeight = 0; + double largestWidth = double.MinValue; + + foreach (var paragraph in body.Paragraphs) + { + ImportParagraph(paragraph, currentHeight); + var addedPara = Paragraphs.Last(); + currentHeight = addedPara.Bounds.Bottom; + largestWidth = Math.Max(largestWidth, addedPara.Bounds.Width); + } + + foreach (var paragraph in body.Paragraphs) + { + SetHorizontalAlignmentPosition(); + } + + if (Paragraphs != null && Paragraphs.Count() > 0) + { + Bounds.Height = currentHeight; + } + + Bounds.Top = GetAlignmentVertical(); + } + + private double GetParagraphAscendantSpacingInPixels(DrawingTextLineSpacing lineSpacingType, double spacingValue, ITextShaper fmExact, float fontSize, out double multiplier) + { + if (lineSpacingType == DrawingTextLineSpacing.Exactly) + { + multiplier = -1; + return spacingValue.PointToPixel(); + } + else + { + multiplier = (spacingValue / 100); + return multiplier * fmExact.GetAscentInPoints(fontSize).PointToPixel(); + } + } + + + //public void AddText(string text, FontMeasurerTrueType measurer) + //{ + // if (Paragraphs.Count == 0) + // { + // AddParagraph(text, measurer); + // } + // else + // { + // Paragraphs.Last().AddText(text, measurer); + // } + //} + //internal void AddText(string text, ExcelTextFont font) + //{ + // //Document Top position for the paragraph text based on vertical alignment + // var posY = GetAlignmentVertical(); + // //var vertAlignAttribute = GetVerticalAlignAttribute(posY); + + // //var measurer = font.PictureRelationDocument.Package.Settings.TextSettings.GenericTextMeasurerTrueType; + // //Limit bounding area with the space taken by previous paragraphs + // //Note that this is ONLY identical to PosY if the vertical alignment is top + + // //The first run in the first paragraph must apply different line-spacing + // //var svgParagraph = new SvgParagraph(text, font, area, vertAlignAttribute, posY); + // var paragraph = CreateParagraph(Bounds); + // paragraph.AddText(text, font); + // paragraph.FillColor = font.Fill.Color.To6CharHexString(); + + // Paragraphs.Add(paragraph); + //} + //public void SetMeasurer(FontMeasurerTrueType fontMeasurer) + //{ + // _measurer = fontMeasurer; + //} + + double? _alignmentY = null; + + /// + /// Get the start of text space vertically + /// + /// + /// + private double GetAlignmentVertical() + { + double alignmentY = 0; + + switch (VerticalAlignment) + { + case eTextAnchoringType.Top: + alignmentY = Bounds.Top; + break; + //Center means center of a Shape's ENTIRE bounding box height. + //Not center of the Inset GetRectangle + case eTextAnchoringType.Center: + alignmentY = (MaxHeight - Bounds.Height)/2 + Bounds.Top; + break; + case eTextAnchoringType.Bottom: + alignmentY = MaxHeight - Bounds.Height; + break; + } + + _alignmentY = alignmentY; + + return _alignmentY.Value; + } + + + /// + /// Each file format defines its own paragraph + /// + /// + internal abstract ParagraphItem CreateParagraph(TextBodyItem textBody, ExcelDrawingParagraph paragraph, BoundingBox parent, string textIfEmpty=""); + + internal abstract ParagraphItem CreateParagraph(TextBodyItem textBody, BoundingBox parent, string textIfEmpty = ""); + + /// + /// Each file format defines its own paragraph + /// + /// + internal abstract ParagraphItem CreateParagraph(TextBodyItem textBody, BoundingBox parent); + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunCollection.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunCollection.cs new file mode 100644 index 0000000000..e59e69e474 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunCollection.cs @@ -0,0 +1,50 @@ +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal class TextRunCollection : IEnumerable + { + private List _textRunItems; + + public void Add(TextRunItem item) + { + _textRunItems.Add(item); + } + + /// + /// Number of items in the collection + /// + public int Count + { + get + { + return _textRunItems.Count; + } + } + IEnumerator IEnumerable.GetEnumerator() + { + return _textRunItems.GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return _textRunItems.GetEnumerator(); + } + /// + /// Returns a textrun at position + /// + /// The position of the chart. 0-base + /// + public TextRunItem this[int PositionID] + { + get + { + return (_textRunItems[PositionID]); + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunItem.cs new file mode 100644 index 0000000000..9670527633 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TextRunItem.cs @@ -0,0 +1,205 @@ +using EPPlus.DrawingRenderer; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text.RegularExpressions; +using static System.Net.Mime.MediaTypeNames; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal abstract class TextRunItem : RenderItem + { + public override RenderItemType Type => RenderItemType.Text; + + internal readonly string _originalText; + protected string _currentText; + + internal protected MeasurementFont _measurementFont; + internal protected bool _isFirstInParagraph; + + internal double FontSizeInPixels { get; private set; } + + public List Lines { get; private set; } + + protected internal bool _isItalic = false; + protected internal bool _isBold = false; + protected internal eUnderLineType _underLineType; + protected internal eStrikeType _strikeType; + protected internal Color _underlineColor; + protected internal double _baseline; + + internal double YPosition { get; set; } + internal double ClippingHeight = double.NaN; + + internal TextRunItem(DrawingBase renderer, BoundingBox parent, MeasurementFont font, string displayText) : base(renderer, parent) + { + _originalText = displayText; + + Bounds.Name = "TextRun"; + _currentText = displayText; + + Lines = Regex.Split(_currentText, "\r\n|\r|\n").ToList(); + + _measurementFont = font; + _isFirstInParagraph = true; + + FontSizeInPixels = ((double)_measurementFont.Size).PointToPixel(true); + Bounds.Height = _measurementFont.Size; + if (parent.Height < _measurementFont.Size) + { + parent.Height = _measurementFont.Size; + } + + //To get clipping height we need to get the textbody bounds + if (parent != null && parent.Parent != null && parent.Parent.Parent != null) + { + ClippingHeight = parent.Parent.Parent.Position.Y + parent.Parent.Parent.Size.Y; + } + if (Lines.Count == 1) + { + //Bounds.Width = parent.Width; + GetBounds(out double il, out double it, out double ir, out double ib); //TODO: remove when calc works + } + else + { + //Measure text. + GetBounds(out double il, out double it, out double ir, out double ib); //TODO: remove when calc works + } + _underLineType = eUnderLineType.None; + } + + internal TextRunItem(DrawingBase renderer, BoundingBox parent, string text, ExcelTextFont font, string displayText) : base(renderer, parent) + { + _originalText = text; + + Bounds.Name = "TextRun"; + _currentText = string.IsNullOrEmpty(displayText) ? _originalText : displayText; + + Lines = Regex.Split(_currentText, "\r\n|\r|\n").ToList(); + + //_measurer = new FontMeasurerTrueType(); + + _measurementFont = font.GetMeasureFont(); + //_measurer.SetFont(_measurementFont); + + _isFirstInParagraph = true; + + //_fontStyles = _measurementFont.Style; + + _baseline = font.Baseline; + if (_baseline != 0) + { + _measurementFont.Size *= (float)(1 - (Math.Abs(_baseline) / 100)); + } + FontSizeInPixels = ((double)_measurementFont.Size).PointToPixel(true); + + Bounds.Height = _measurementFont.Size; + if (parent.Height < _measurementFont.Size) + { + parent.Height = _measurementFont.Size; + } + //_horizontalTextAlignment = TextAlignment.Center; + + if (font.Fill.Style == eFillStyle.SolidFill) + { + FillColor = "#" + font.Fill.Color.To6CharHexString(); + } + + //To get clipping height we need to get the textbody bounds + if (parent != null && parent.Parent != null && parent.Parent.Parent != null) + { + ClippingHeight = parent.Parent.Parent.Position.Y + parent.Parent.Parent.Size.Y; + } + if(Lines.Count==1) + { + //Bounds.Width = parent.Width; + GetBounds(out double il, out double it, out double ir, out double ib); //TODO: remove when calc works + } + else + { + //Measure text. + GetBounds(out double il, out double it, out double ir, out double ib); //TODO: remove when calc works + } + _isItalic = font.Italic; + _isBold = font.Bold; + _underLineType = font.UnderLine; + _underlineColor = font.UnderLineColor; + _strikeType = font.Strike; + } + + /// + /// If the run has been wrapped more line-breaks may have been added in displayText + /// + /// + /// + /// + internal TextRunItem(DrawingBase renderer, BoundingBox parent, ExcelParagraphTextRunBase run, string displayText = "") : base(renderer, parent) + { + _originalText = run.Text; + + Bounds.Name = "TextRun"; + _currentText = string.IsNullOrEmpty(displayText) ? _originalText : displayText; + + Lines = Regex.Split(_currentText, "\r\n|\r|\n").ToList(); + + _measurementFont = run.GetMeasurementFont(); + + + //_fontStyles = _measurementFont.Style; + + _baseline = run.Baseline; + FontSizeInPixels = ((double)_measurementFont.Size).PointToPixel(true); + + Bounds.Height = _measurementFont.Size; + + //_horizontalTextAlignment = run.Paragraph.HorizontalAlignment; + + if (run.Fill.IsEmpty == false && run.Fill.Style == eFillStyle.SolidFill) + { + FillColor = "#" + run.Fill.Color.To6CharHexString(); + } + + //To get clipping height we need to get the textbody bounds + if( parent!= null && parent.Parent != null && parent.Parent.Parent != null) + { + ClippingHeight = ((BoundingBox)parent.Parent.Parent).Bottom; + } + + if (run.Fill.Style == eFillStyle.SolidFill) + { + FillColor = "#" + run.Fill.Color.To6CharHexString(); + } + + _isItalic = run.FontItalic; + _isBold = run.FontBold; + _underLineType = run.FontUnderLine; + _underlineColor = run.UnderLineColor; + _strikeType = run.FontStrike; + } + + /// + /// Calculates right/bottom + /// + /// + /// + /// + /// + internal override void GetBounds(out double il, out double it, out double ir, out double ib) + { + il = Bounds.Left; + it = Bounds.Top; + ir = Bounds.Right; + ib = Bounds.Bottom; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Shared/TransformGroup.cs b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TransformGroup.cs new file mode 100644 index 0000000000..d5b002ac66 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Shared/TransformGroup.cs @@ -0,0 +1,100 @@ +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System.Collections.Generic; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal abstract class TransformGroup : RenderItem + { + protected InnerGroup _innerGroup; + + Point PositionAfterTransform; + + /// + /// In degrees + /// + internal double Rotation = double.NaN; + + BoundingBox _altRotationPoint = null; + + internal BoundingBox RotationPoint + { + get + { + if (_altRotationPoint == null) + { + return Bounds; + } + return _altRotationPoint; + } + set + { + _altRotationPoint = value; + } + } + Coordinate _scale = new Coordinate(1,1); + + internal Coordinate Scale + { + get + { + return _scale; + } + set + { + Bounds.Parent.Scale = new Graphics.Math.Vector2(value.X, value.Y); + _scale = value; + } + } + + public TransformGroup(DrawingBase renderer) : base(renderer) + { + _innerGroup = CreateInnerGroup(); + _innerGroup.Bounds.Parent = Bounds; + } + + public TransformGroup(DrawingBase renderer, double localXPos, double localYPos) : this(renderer) + { + Bounds.Left = localXPos; + Bounds.Top = localYPos; + } + + + public TransformGroup(DrawingBase renderer, BoundingBox parent, double rotation, Transform rotationPoint = null) : this(renderer, 0, 0) + { + Bounds.Parent = parent; + Rotation = rotation; + if (rotationPoint != null) + { + RotationPoint = new BoundingBox(rotationPoint.LocalPosition.X, rotationPoint.LocalPosition.Y); + } + } + + internal void SetRotationPointToCenterOfGroup(double rotation = double.NaN) + { + RotationPoint = new BoundingBox(Bounds.Width / 2, Bounds.Height / 2); + + if (double.IsNaN(rotation) == false) + { + Rotation = rotation; + } + } + + /// + /// Adds child item to the group under this group + /// + /// + internal void AddChildItem(RenderItem item) + { + _innerGroup.AddChildItem(item); + + Bounds.Width = item.Bounds.Right > Bounds.Width ? item.Bounds.Right : Bounds.Width; + Bounds.Height = item.Bounds.Bottom > Bounds.Height ? item.Bounds.Bottom : Bounds.Height; + } + + internal abstract InnerGroup CreateInnerGroup(); + + public override RenderItemType Type => RenderItemType.Group; + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgDrawingCommands.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgDrawingCommands.cs new file mode 100644 index 0000000000..b5087795db --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgDrawingCommands.cs @@ -0,0 +1,181 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +//using OfficeOpenXml.Drawing; +//using OfficeOpenXml.Utils.TypeConversion; +//using System; +//using System.Reflection; +//using System.Textbox.Json; +//using System.Windows; +//using System.Xml; +//namespace EPPlusImageRenderer.RenderItems +//{ +// public static class SvgDrawingCommands +// { +// public static void LoadShapes() +// { +// Shapes.Clear(); +// var br = new BinaryReader(new FileStream("c:\\temp\\Shapedrawing.bin", FileMode.Open)); +// while (br.BaseStream.Position < br.BaseStream.Length) +// { +// var shapeStyle = (eShapeStyle)br.ReadByte(); +// var list = new List(); +// var adj = ShapeAdjustments.ContainsKey(shapeStyle) ? ShapeAdjustments[shapeStyle] : null; +// Shapes.Add(shapeStyle, list); +// var ix = 0; +// do +// { +// var recType = br.ReadByte(); +// if (recType == 0) break; +// SvgAdjustmentPoint adjPoint = null; +// if (adj != null && adj.ContainsKey(ix & 0x1FF)) +// { +// adjPoint = adj[ix]; +// } + +// switch (recType) +// { +// case 1: //rect +// list.Add(ReadRect(br)); +// break; +// case 2: //path +// list.Add(ReadPath(br)); +// break; +// } +// ix++; +// } +// while (br.BaseStream.Position < br.BaseStream.Length); +// } +// } + +// private static SvgRenderPathItem ReadPath(BinaryReader br) +// { +// var fill = br.ReadByte(); +// var stroke = br.ReadByte(); +// var commandCount = br.ReadByte(); +// var item = new SvgRenderPathItem(); +// for (var i = 0; i < commandCount; i++) +// { +// var ct = (PathCommandType)br.ReadByte(); +// var itemCount = br.ReadInt16(); +// var l = new List(); +// for (int j = 0; j < itemCount; j++) +// { +// l.Add(br.ReadSingle()); +// } +// var cmd = new PathCommands(ct, item, l.ToArray()); +// //if (adj != null && (adj.Commands == null || adj.Commands.Any(x => x.Index == i))) +// //{ +// // cmd.AdjustmentPoint = adj; +// // if (adj.Commands != null) +// // { +// // cmd.CommandIndex = adj.Commands.FindIndex(x => x.Index == i); +// // } +// //} +// item.Commands.Add(cmd); +// } + +// item.FillColorSource = (PathFillMode)fill; +// item.BorderColorSource = (PathFillMode)stroke; + +// return item; +// } + +// private static SvgRenderRectItem ReadRect(BinaryReader br) +// { +// var fill = br.ReadByte(); +// var stroke = br.ReadByte(); +// var x = br.ReadSingle(); +// var y = br.ReadSingle(); +// var width = br.ReadSingle(); +// var height = br.ReadSingle(); + +// return new SvgRenderRectItem() { Left = x, Top = y, Width = width, Height = height, FillColorSource = (PathFillMode)fill, BorderColorSource = (PathFillMode)stroke }; +// } +// public static string SerializeShapeAdjustments() +// { +// var s = JsonSerializer.Serialize(ShapeAdjustments); +// return new StringReader(s).ReadToEnd(); +// } +// public static void DeSerializeShapeAdjustments(string json) +// { +// ShapeAdjustments.Clear(); +// LoadShapes(); +// //MessageBox.Show("Json Loaded"); +// } + +// public static void LoadAdjustments() +// { +// var path = new FileInfo(Assembly.GetExecutingAssembly().FullName).DirectoryName; +// ShapeAdjustments = new Dictionary>(); +// foreach (var f in Directory.GetFiles(path + "\\Adjustments\\", "*.xml")) +// { +// ReadAdjustmentXml(f, ShapeAdjustments); +// } +// } + +// private static void ReadAdjustmentXml(string f, Dictionary> shapeAdjustments) +// { +// var xml = new XmlDocument(); +// xml.Load(f); + +// var style = (eShapeStyle)Enum.Parse(typeof(eShapeStyle), xml.SelectSingleNode("adjust/@type").Value); +// var adjs = new Dictionary(); +// foreach (XmlElement objNode in xml.SelectNodes("adjust/objects/object")) +// { +// var adj = new SvgAdjustmentPoint(); +// adj.ItemIndex = int.Parse(objNode.GetAttribute("ix")); +// adj.AdjustmentType = (AdjustmentType)Enum.Parse(typeof(AdjustmentType), objNode.GetAttribute("adjustmentType")); +// foreach (XmlElement cmdNode in objNode.SelectNodes("commands/command")) +// { +// var ix = int.Parse(cmdNode.GetAttribute("ix")); +// var cmd = new SvgCommand(ix); +// if (adj.Commands == null) adj.Commands = new List(); +// adj.Commands.Add(cmd); +// foreach (XmlElement ptNode in cmdNode.SelectNodes("pt")) +// { +// var ptIx = short.Parse(ptNode.GetAttribute("ix")); +// var coordinate = new SvgCoordinate(ptIx); +// if (string.IsNullOrEmpty(ptNode.GetAttribute("adjustPointName"))==false) +// { +// coordinate.PointName = ptNode.GetAttribute("adjustPointName"); +// } +// else +// { +// coordinate.PointName = ""; +// } + +// if (ConvertUtil.TryParseIntString(ptNode.GetAttribute("origin"), out int r)) +// { +// coordinate.Origin = (short)r; +// } +// else +// { +// coordinate.Origin = 0; +// } +// if (Enum.TryParse(ptNode.GetAttribute("type"), true, out var result)) +// { +// coordinate.BulletType = result; +// } +// cmd.Coordinates.Add(ptIx, coordinate); +// } +// } +// adjs.Add(adj.ItemIndex, adj); +// } +// shapeAdjustments.Add(style, adjs); +// } + +// internal static Dictionary> Shapes { get; } = new Dictionary>(); +// internal static Dictionary> ShapeAdjustments { get; set; } = new Dictionary>(); +// } + +//} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgExtensions.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgExtensions.cs new file mode 100644 index 0000000000..93c3ac7124 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgExtensions.cs @@ -0,0 +1,45 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; + +namespace EPPlusImageRenderer.RenderItems +{ + public static class SvgExtensions + { + public static char AsCommandChar(this PathCommandType type) + { + switch (type) + { + case PathCommandType.Move: + return 'M'; + case PathCommandType.Line: + return 'L'; + case PathCommandType.HorizontalLine: + return 'H'; + case PathCommandType.VerticalLine: + return 'V'; + case PathCommandType.CubicBézier: + return 'C'; + case PathCommandType.QuadraticBézier: + return 'Q'; + case PathCommandType.Arc: + return 'A'; + case PathCommandType.End: + return 'Z'; + default: + throw new NotImplementedException("SVG path type not implemented"); + } + } + } + +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/ConnectionPointsMiddle.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/ConnectionPointsMiddle.cs new file mode 100644 index 0000000000..f519ec5d3a --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/ConnectionPointsMiddle.cs @@ -0,0 +1,34 @@ +using EPPlus.DrawingRenderer; + +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + public class ConnectionPointsMiddle + { + public Coordinate Left; + public Coordinate Top; + public Coordinate Right; + public Coordinate Bottom; + + public Dictionary Points = new Dictionary(); + + public ConnectionPointsMiddle(double left, double top, double width, double height) + { + var middleWidth = width / 2; + var middleHeight = height / 2; + + var middleX = left + middleWidth; + var middleY = top + middleHeight; + + Left = new Coordinate(left, middleY); + Top = new Coordinate(middleX, top); + + Right = new Coordinate(left + width, middleY); + Bottom = new Coordinate(left + middleX, top + height); + + Points.Add(0, Left); + Points.Add(1, Top); + Points.Add(2, Right); + Points.Add(3, Bottom); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgParagraphRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgParagraphRenderItem.cs new file mode 100644 index 0000000000..06599819d6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgParagraphRenderItem.cs @@ -0,0 +1,46 @@ +using EPPlus.DrawingRenderer; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; + + +namespace EPPlus.DrawingRenderer.RenderItems.SvgItem +{ + public class SvgParagraphRenderItem : ParagraphRenderItem + { + public SvgParagraphRenderItem(RenderContext renderContext, RenderTextBody body, BoundingBox parent, string text, bool setDefaultFont = true) : base(renderContext, parent, body, text, setDefaultFont) + { + ImportStyles(); + } + public SvgParagraphRenderItem(RenderContext renderContext, RenderTextBody textBody, BoundingBox parent, IRichTextFormatSimple rtFormat) : base(renderContext, parent, textBody, rtFormat) + { + ImportStyles(); + } + + private void ImportStyles() + { + //Import RichText data to each run + foreach (var run in Runs) + { + var textRun = (SvgTextRunRenderItem)run; + var rtOptions = _layoutSystem.InputFragments[run.OriginalRtIdx].RichTextOptions; + if (_layoutSystem.InputFragments.Count != 0 && run.OriginalRtIdx != -1 && rtOptions is IRichTextFormatSimple) + { + textRun.ImportRichTextData((IRichTextFormatSimple)rtOptions); + } + else + { + //If not use the default for the whole paragraph (potentially user specified) + run.ImportFontData(DefaultParagraphFont); + } + } + } + + public override RenderItemType Type => RenderItemType.Paragraph; + + protected override TextRunRenderItem CreateTextRun(BoundingBox parent, string displayText, int origRtIdx) + { + return new SvgTextRunRenderItem(parent, displayText, origRtIdx); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextBodyRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextBodyRenderItem.cs new file mode 100644 index 0000000000..8716dae0ce --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextBodyRenderItem.cs @@ -0,0 +1,30 @@ +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; +using System.Drawing; + + +namespace EPPlus.DrawingRenderer.RenderItems.SvgItem +{ + public class SvgTextBodyRenderItem : RenderTextBody + { + public SvgTextBodyRenderItem(RenderContext renderContext, BoundingBox parent, bool autoSize) : base(renderContext, parent, autoSize) + { + } + + public SvgTextBodyRenderItem(RenderContext renderContext, BoundingBox parent, double left, double top, double maxWidth, double maxHeight, bool clampedToParent = false, bool autoSize = false) : base(renderContext, parent, left, top, maxWidth, maxHeight, clampedToParent, autoSize) + { + + } + + protected override ParagraphRenderItem CreateParagraph(BoundingBox parent, string textIfEmpty = "") + { + return new SvgParagraphRenderItem(RenderContext, this, parent, textIfEmpty); + } + + protected override ParagraphRenderItem CreateParagraph(BoundingBox parent, IRichTextFormatSimple richText) + { + return new SvgParagraphRenderItem(RenderContext, this, parent, richText); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextRunRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextRunRenderItem.cs new file mode 100644 index 0000000000..3971adac4c --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/SvgTextRunRenderItem.cs @@ -0,0 +1,39 @@ +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Graphics; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.DrawingRenderer.RenderItems.SvgItem +{ + public class SvgTextRunRenderItem : TextRunRenderItem + { + public SvgTextRunRenderItem(BoundingBox parent) : base(parent) + { + } + + public SvgTextRunRenderItem(BoundingBox parent, string text, int origRtIdx) : base(parent, text, origRtIdx) + { + } + + public SvgTextRunRenderItem(BoundingBox parent, IFontFormatBase font, string displayText, bool renderTextNode = false) : base(parent, font, displayText) + { + RenderTextNode = renderTextNode; + } + + public SvgTextRunRenderItem(BoundingBox parent, string text, IFontFormatBase font, string displayText) : base(parent, text, font, displayText) + { + } + + + /// + /// If set to true will render its own parent Text Node + /// Will not work properly within paragraphs + /// + internal bool RenderTextNode { get; private set; } = false; + + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/eTextAnchor.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/eTextAnchor.cs new file mode 100644 index 0000000000..762d32e686 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgItem/eTextAnchor.cs @@ -0,0 +1,21 @@ +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + /// + /// Matches the enum for an svg text anchor of a text element. + /// + public enum eTextAnchor + { + /// + /// Text is anchored to the start of the text element. + /// + Start, + /// + /// Text is anchored in the center of the text element. + /// + Middle, + /// + /// Text is anchored in the end of the text element. + /// + End + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/SvgLineJoin.cs b/src/EPPlus.DrawingRenderer/RenderItems/SvgLineJoin.cs new file mode 100644 index 0000000000..9b1e1afc04 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/SvgLineJoin.cs @@ -0,0 +1,24 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlusImageRenderer.RenderItems +{ + internal enum SvgLineJoin + { + Arcs, + Bevel, + Miter, + MiterClip, + Round + } + +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/ParagraphRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/ParagraphRenderItem.cs new file mode 100644 index 0000000000..3b54e73264 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/ParagraphRenderItem.cs @@ -0,0 +1,408 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.Textbox; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.Integration.RichText; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Graphics; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Shared +{ + /// + /// Text alignment + /// + public enum TextAlignment + { + /// + /// Left alignment + /// + Left, + /// + /// Center alignment + /// + Center, + /// + /// Right alignment + /// + Right, + /// + /// Distributes the text words across an entire text line + /// + Distributed, + /// + /// Align text so that it is justified across the whole line. + /// + Justified, + /// + /// Aligns the text with an adjusted kashida length for Arabic text + /// + JustifiedLow, + /// + /// Distributes Thai text specially, specially, because each character is treated as a word + /// + ThaiDistributed + } + + public enum TextLineSpacing + { + /// + /// Single line spacing + /// + Single, + /// + /// 1.5 lines + /// + OneAndAHalf, + /// + /// Double line spacing + /// + Double, + /// + /// Exact point spacing + /// + Exactly, + /// + /// Multiple line spacing + /// + Multiple + } + + public abstract class ParagraphRenderItem : RenderItem + { + protected double LeftMargin { get; set; } + protected double RightMargin { get; set; } + protected double LineSpacingAscendantOnly { get; set; } + protected bool IsFirstParagraph { get; set; } + + protected LayoutSystem _layoutSystem; + + protected RichTextCollectionBase _textFragments = new RichTextCollectionBase(); + + public double ParagraphLineSpacing { get; protected set; } + + protected TextAlignment _alignment; + + //After setting alignment we must re-calculate the rows + public TextAlignment HorizontalAlignment { get { return _alignment; } set { _alignment = value; WrapTextFragmentsAndGenerateTextRuns(); } } + public List Runs { get; set; } = new List(); + public TextLineCollection Lines { get; protected set; } + public bool DisplayBounds { get; set; } = false; + + public override RenderItemType Type => RenderItemType.Paragraph; + + public bool AutoSize = false; + + public FontFormatBase DefaultParagraphFont; + + protected double ParentMaxWidth; + protected double ParentMaxHeight; + + protected RenderTextBody ParentTextBody { get; set; } + + protected double? _lsMultiplier = null; + + protected bool TextIfEmptyIsNull { get; set; } + + protected bool LinespacingIsExact + { + get + { + return _lsMultiplier.HasValue == false; + } + } + + protected RenderContext RenderContext { get; private set; } + + + + protected TextLineSpacing _lsType; + protected double? _centerAdjustment; + + protected ParagraphRenderItem(RenderContext renderContext, BoundingBox parent, bool setFallbackDefaultFont = true) : base(parent) + { + RenderContext = renderContext; + Bounds.Name = "Paragraph"; + if (setFallbackDefaultFont) + { + var defaultFont = new MeasurementFont { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Regular }; + DefaultParagraphFont = new FontFormatBase(defaultFont); + FillColor = "black"; + } + } + + protected ParagraphRenderItem(RenderContext renderContext, BoundingBox parent, RenderTextBody textBody, bool setFallbackDefaultFont = true) + : this(renderContext, parent, setFallbackDefaultFont) + { + InitBasedOnParent(textBody); + Bounds.Name = "Paragraph"; + } + + protected ParagraphRenderItem(RenderContext renderContext, BoundingBox parent, RenderTextBody textBody, string text, bool setFallbackDefaultFont = true) + : this(renderContext, parent, textBody, setFallbackDefaultFont) + { + _lsMultiplier = 1d; + ImportLinesAndTextRunsBase(text); + } + + protected ParagraphRenderItem(RenderContext renderContext, BoundingBox parent, RenderTextBody textBody, IRichTextFormatSimple rtFormat) + : this(renderContext, parent, textBody, false) + { + _lsMultiplier = 1d; + DefaultParagraphFont = new FontFormatBase(rtFormat.Family, rtFormat.SubFamily, rtFormat.Size); + AddRichText(rtFormat); + } + + protected ParagraphRenderItem(RenderContext renderContext, BoundingBox parent, RenderTextBody textBody, IRichTextFormatDrawing rtFormat) + : this(renderContext, parent, textBody, false) + { + AddRichText(rtFormat); + } + + protected double GetAlignmentHorizontal(TextAlignment txAlignment) + { + double x = 0; + switch (txAlignment) + { + case TextAlignment.Left: + default: + x = Bounds.Left + LeftMargin; + break; + case TextAlignment.Center: + x = (Bounds.Right / 2) + LeftMargin - RightMargin; + break; + case TextAlignment.Right: + x = Bounds.Right - RightMargin; + break; + } + + return x; + } + + + void InitBasedOnParent(RenderTextBody textBody) + { + ParentTextBody = textBody; + ParentMaxWidth = textBody.MaxWidth; + ParentMaxHeight = textBody.MaxHeight; + AutoSize = textBody.AutoSize; + + if (AutoSize == false) + { + Bounds.Width = textBody.Width; + Bounds.Height = textBody.Height; + } + else + { + //Set to max until measured + Bounds.Width = ParentMaxWidth; + Bounds.Height = ParentMaxHeight; + } + } + + TextLineCollection WrapFragmentsToLines(List? fragments = null) + { + //This is highly innefficent. Really, LayoutSystem should be + //Holding the fragments from the start/wrapping should only be done when textFragments are fully complete + _layoutSystem = new LayoutSystem(RenderContext.FontEngine, _textFragments); + + //if (fragments == null && _layoutSystem == null) + //{ + // _layoutSystem = new LayoutSystem(_textFragments); + //} + + double maxWidthInPoints; + if(AutoSize) + { + maxWidthInPoints = Math.Round(ParentMaxWidth - RightMargin - LeftMargin, 0, MidpointRounding.AwayFromZero); + } + else + { + maxWidthInPoints = Bounds.Width; + } + return _layoutSystem.Wrap(maxWidthInPoints); + } + + private void AddRichTextBase(IRichTextFormatSimple rt) + { + if (_textFragments == null) + { + _textFragments = new RichTextCollectionBase(); + } + + if (string.IsNullOrEmpty(rt.Text) == false) + { + _textFragments.Add(rt); + } + } + + protected void AddDefaultTextFragment(string text) + { + var defaults = new RichTextFormatSimple(); + defaults.Text = text; + defaults.SetFont(DefaultParagraphFont); + + AddRichTextBase(defaults); + } + + protected void ImportLinesAndTextRunsBase(string textIfEmpty) + { + if(string.IsNullOrEmpty(textIfEmpty)) + { + TextIfEmptyIsNull = true; + } + else + { + TextIfEmptyIsNull = false; + } + + AddDefaultTextFragment(textIfEmpty); + WrapTextFragmentsAndGenerateTextRuns(); + } + + protected void WrapTextFragmentsAndGenerateTextRuns() + { + Lines = WrapFragmentsToLines(); + Runs.Clear(); + + //In points + double widthOfLargestLine = 0; + //Set to 0 then grow to size of content after wrap/measure + //This as an empty paragraph should have no real size + double combinedHeight = 0; + + //has value if there is linespacing otherwise isNaN + //Don't do this on the actual property as a paragraph can have a fallback linespacing without it being applied + //(e.g. paragraph linespacing is set in the ooxml but the paragraph contains no textruns) + //We should not change the 'ParagraphLineSpacing' variable directly here + double lineSpacingResult = LinespacingIsExact ? ParagraphLineSpacing : double.NaN; + + if (Lines != null && Lines.Count != 0) + { + widthOfLargestLine = Lines.LargestWidthWithoutSpace; + combinedHeight = Lines.GetHeightOfCollection(_lsMultiplier, lineSpacingResult); + + + Bounds.Width = widthOfLargestLine + RightMargin; + //SetHorizontalAlignment(widthOfLargestLine); + + int lineIdx = 0; + foreach (var line in Lines) + { + double lineDist = widthOfLargestLine - line.GetWidthWithoutTrailingSpaces(); + double prevWidth = CalculatePrevWidthBasedOnAlignment(lineDist); + + foreach (var lineFragment in line.LineFragments) + { + var displayText = lineFragment.Text; + + int rtIdx = -1; + if (_layoutSystem != null && lineFragment.OriginalTextFragment != null && _layoutSystem.InputFragments.Count > 0) + { + rtIdx = _layoutSystem.InputFragments.IndexOf(lineFragment.OriginalTextFragment); + } + + var run = CreateTextRun(Bounds, displayText, rtIdx); + //Potentially we could import styling here instead but that leads to multiple issues. + //We may need to move it back here for auto-size reasons + + run.YPosition = Lines.GetBaseLinePosition(lineIdx, lineSpacingResult); + run.Bounds.Left = prevWidth; + run.Bounds.Width = lineFragment.Width; + prevWidth += lineFragment.Width; + + Runs.Add(run); + } + lineIdx++; + } + } + Bounds.Height = combinedHeight; + } + + protected double CalculatePrevWidthBasedOnAlignment(double lineDist) + { + double prevWidth = 0; + if (HorizontalAlignment == TextAlignment.Center) + { + //Calculate difference in widths and split to get offset between leftmost position and current line + prevWidth = lineDist / 2; + } + else if (HorizontalAlignment == TextAlignment.Right) + { + //Note that the actual bounds with the space will be outside max bounds. + //This appears to be how excel does it + prevWidth = lineDist; + } + + return prevWidth; + } + + protected void SetHorizontalAlignment(double widthOfLargestLine) + { + if (HorizontalAlignment == TextAlignment.Center) + { + //Bounds of the paragraph should be bounds of the text itself. + //Therefore we must know the starting point to set accurate left and offset from left. + Bounds.Left = GetAlignmentHorizontal(HorizontalAlignment) - (widthOfLargestLine / 2); + } + else + { + //Bounds of the paragraph should be bounds of the text itself. + //Therefore we must know the starting point to set accurate left and offset from left. + Bounds.Left = 0; + } + } + + void ImportStyles() + { + foreach (var run in Runs) + { + var rt = _layoutSystem.InputFragments[run.OriginalRtIdx].RichTextOptions; + if(rt is RichTextFormatDrawing) + { + //Import drawing data + run.ImportRichTextData((RichTextFormatDrawing)rt); + } + else if(rt is IRichTextFormatSimple) + { + //Import basic/cell data + run.ImportRichTextData((IRichTextFormatSimple)rt); + } + else + { + //Import only essential font data + run.ImportFontData((IFontFormatBase)rt); + } + } + } + + public void AddRichText(IRichTextFormatSimple richText) + { + //TODO: Fix superScript/subScript should apply baseLine changes appropriately + + AddRichTextBase(richText); + WrapTextFragmentsAndGenerateTextRuns(); + } + + public void AddRichText(IRichTextFormatDrawing richText) + { + //adjust size in accordance with baseline + richText.Size = richText.Baseline == 0 ? richText.Size : (float)(richText.Size * (1 - (Math.Abs(richText.Baseline) / 100))); + + AddRichTextBase(richText); + WrapTextFragmentsAndGenerateTextRuns(); + ImportStyles(); + } + + public void AddText(string text) + { + ImportLinesAndTextRunsBase(text); + ImportStyles(); + } + + protected abstract TextRunRenderItem CreateTextRun(BoundingBox parent, string displayText, int origRtIdx); + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs new file mode 100644 index 0000000000..f487503c84 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs @@ -0,0 +1,268 @@ +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + /// + /// Text anchoring + /// + public enum TextAnchoringType + { + /// + /// Anchor the text to the bottom + /// + Bottom, + /// + /// Anchor the text to the center + /// + Center, + /// + /// Anchor the text so that it is distributed vertically. + /// + Distributed, + /// + /// Anchor the text so that it is justified vertically. + /// + Justify, + /// + /// Anchor the text to the top + /// + Top + } + + public abstract class RenderTextBody : GroupRenderItem + { + public RenderTextBody(RenderContext renderContext, BoundingBox parent, bool autoSize) + { + RenderContext = renderContext; + Bounds.Parent = parent; + AutoSize = autoSize; + MaxWidth = parent.Width; + MaxHeight = parent.Height; + Bounds.Name = "Textbody"; + } + public RenderTextBody(RenderContext renderContext, BoundingBox parent, double left, double top, double maxWidth, double maxHeight, bool clampedToParent = false, bool autoSize=false) : this(renderContext, parent, autoSize) + { + RenderContext = renderContext; + Bounds.Left = left; + Bounds.Top = top; + Bounds.Width = maxWidth; + Bounds.Height = maxHeight; + MaxWidth = maxWidth; + MaxHeight = maxHeight; + Bounds.Name = "Textbody"; + } + + protected RenderContext RenderContext { get; private set; } + public List Paragraphs { get; set; } = new List(); + + public TextAnchoringType VerticalAlignment = TextAnchoringType.Top; + public string Text { get; set; } + public double MaxWidth { get; set; } + public double MaxHeight { get; set; } + /// + /// Shorthand for Bounds.Width + /// + public double Width { get { return Bounds.Width; } set { Bounds.Width = value; } } + + /// + /// Shorthand for Bounds.Height + /// + public double Height { get { return Bounds.Height; } set { Bounds.Height = value; } } + + public bool AutoSize { get; set; } + public double TopMargin { get; set; } + public double BottomMargin { get; set; } + public double RightMargin { get; set; } + public double LeftMargin { get; set; } + public string FontColorString { get; set; } + + + public void AppendRenderItems(List renderItems) + { + //foreach(var item in Paragraphs) + //{ + // AddChildItem(item); + //} + //GroupRenderItem groupItem; + //if (Bounds.Parent.Rotation == 0) //If the parent is rotated, we should not apply rotation again. This is usually when the parent is a textbox. + //{ + // groupItem = new GroupRenderItem(Bounds, Bounds.Rotation); + //} + //else + //{ + // groupItem = new GroupRenderItem(Bounds); + //} + + //if (FontColorString != null) + //{ + // groupItem.GroupTransform += $" fill=\"{FontColorString}\""; + //} + //renderItems.Add(groupItem); + + //Set bounds position to be translation + //Posibly remove translationOffset and make it always be bounds? + //But then we will have an inaccurate bounding box if a child object has negative position. + //TranslationOffset.Left = Bounds.Left; + //TranslationOffset.Top = Bounds.Top; + + renderItems.Add(this); + + var titleItem = new TitleRenderItem("TextBody group"); + AddChildItem(titleItem); + foreach (var item in Paragraphs) + { + AddChildItem(item); + } + } + + public ParagraphRenderItem AddParagraph(IRichTextFormatSimple rtFormat) + { + var paragraph = CreateParagraph(Bounds, rtFormat); + AdjustAndAddParagraph(paragraph); + return paragraph; + } + + public ParagraphRenderItem AddParagraph(string text = null) + { + var paragraph = CreateParagraph(Bounds, text); + AdjustAndAddParagraph(paragraph); + return paragraph; + } + + public void ApplyAutoSize() + { + if (AutoSize) + { + var currentHeight = 0d; + var currentWidth = 0d; + + foreach(var paragraph in Paragraphs) + { + currentHeight += paragraph.Bounds.Height; + + if (currentWidth < paragraph.Bounds.Width || currentWidth == MaxWidth) + { + currentWidth = paragraph.Bounds.Width; + } + } + + Bounds.Width = currentWidth; + Bounds.Height = currentHeight; + } + } + + /// + /// If text is added to the first paragraph without using textbody e.g. Paragraphs[0].AddText() + /// Subsequent paragraphs must be updated + /// + public void RecalculateParagraphs() + { + if(Paragraphs != null && Paragraphs.Count != 0) + { + double lastParagraphBottom = Paragraphs[0].Bounds.Top; + + double smallestLeft = double.MaxValue; + double largestWidth = double.MinValue; + double totalHeight = 0; + + foreach (var paragraph in Paragraphs) + { + paragraph.Bounds.Top = lastParagraphBottom; + lastParagraphBottom = paragraph.Bounds.Bottom; + + smallestLeft = Math.Min(smallestLeft, paragraph.Bounds.Left); + largestWidth = Math.Max(largestWidth, paragraph.Bounds.Width); + totalHeight += paragraph.Bounds.Height; + } + + ContentBounds.Top = Paragraphs[0].Bounds.Top; + ContentBounds.Left = smallestLeft; + ContentBounds.Width = largestWidth; + ContentBounds.Height = totalHeight; + + if (AutoSize) + { + Bounds.Height = totalHeight; + Bounds.Width = ContentBounds.Width; + } + } + } + + /// + /// The total bounds of all paragraphs without margins + /// + protected BoundingBox ContentBounds = new BoundingBox(); + + private void AdjustAndAddParagraph(ParagraphRenderItem paragraph) + { + paragraph.Bounds.Name = $"Container{Paragraphs.Count}"; + paragraph.Bounds.Top = GetTopToAddNextParagraphAt(); + + if (AutoSize) + { + if (Paragraphs.Count == 0) + { + Bounds.Height = paragraph.Bounds.Height; + } + else + { + Bounds.Height += paragraph.Bounds.Height; + } + + if (Bounds.Width < paragraph.Bounds.Width || (Bounds.Width == MaxWidth && Paragraphs.Count == 0)) + { + Bounds.Width = paragraph.Bounds.Width; + } + } + Paragraphs.Add(paragraph); + RecalculateParagraphs(); + } + + private double GetTopToAddNextParagraphAt() + { + double paragraphTop = 0; + + if (Paragraphs.Count != 0) + { + paragraphTop = Paragraphs.Last().Bounds.Bottom; + } + return paragraphTop; + } + + + /// + /// Get the start of text space vertically + /// + /// + public double GetAlignmentVertical() + { + double alignmentY = 0; + + switch (VerticalAlignment) + { + case TextAnchoringType.Top: + alignmentY = Bounds.Top; + break; + //Center means center of a Shape's ENTIRE bounding box height. + //Not center of the Inset GetRectangle + case TextAnchoringType.Center: + if(AutoSize == false) + { + alignmentY = (Bounds.Height) / 2 - ContentBounds.Height; + } + break; + case TextAnchoringType.Bottom: + alignmentY = Bounds.Height - ContentBounds.Height; + break; + } + + return alignmentY; + } + + protected abstract ParagraphRenderItem CreateParagraph(BoundingBox parent, string textIfEmpty = ""); + + protected abstract ParagraphRenderItem CreateParagraph(BoundingBox parent, IRichTextFormatSimple richText); + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextRunCollection.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextRunCollection.cs new file mode 100644 index 0000000000..09e9e3e3ce --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextRunCollection.cs @@ -0,0 +1,45 @@ +using System.Collections; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Shared +{ + internal class RenderTextRunCollection : IEnumerable + { + private List _textRunItems; + + public void Add(TextRunRenderItem item) + { + _textRunItems.Add(item); + } + + /// + /// Number of items in the collection + /// + public int Count + { + get + { + return _textRunItems.Count; + } + } + IEnumerator IEnumerable.GetEnumerator() + { + return _textRunItems.GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return _textRunItems.GetEnumerator(); + } + /// + /// Returns a textrun at position + /// + /// The position of the chart. 0-base + /// + public TextRunRenderItem this[int PositionID] + { + get + { + return (_textRunItems[PositionID]); + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs new file mode 100644 index 0000000000..7939b54198 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs @@ -0,0 +1,252 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.Utils; +using EPPlus.Graphics; +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + public class RenderTextbox : DrawingObject + { + public RenderTextbox(BoundingBox parent, double left, double top, double width, double height, double maxWidth = double.NaN, double maxHeight = double.NaN) + { + Init(parent, maxWidth, maxHeight); + Left = left; + Top = top; + } + + public void Init(BoundingBox parent, double maxWidth, double maxHeight) + { + Parent = parent; + _group = new GroupRenderItem(Parent); + _rectangle = new RectRenderItem(_group.Bounds); + _marginGroup = new GroupRenderItem(_group.Bounds); + //TextBody = new RenderTextBody(Rectangle.Bounds, true); + //TextBody.MaxWidth = maxWidth; + //TextBody.MaxHeight = maxHeight; + } + + public RenderTextbox(BoundingBox parent, double maxWidth, double maxHeight) + { + Init(parent, maxWidth, maxHeight); + } + + //The origin point of the entire textbox itself (its outermost left and top point) + protected GroupRenderItem _group; + //The origin point of the textbody after applied margins + protected GroupRenderItem _marginGroup; + + + protected RectRenderItem _rectangle =null; + public RectRenderItem Rectangle + { + get + { + _rectangle.Bounds.Width = Width; + _rectangle.Bounds.Height = Height; + return _rectangle; + } + set + { + _rectangle = value; + } + } + + RenderTextBody _textBody; + + public virtual RenderTextBody TextBody + { + get { return _textBody; } + set + { _textBody = value; + //Margins should affect textbody global position in real-time + _textBody.Bounds.Parent = _marginGroup.Bounds; + } + } + public double Left + { + get + { + return _group.Bounds.Left; + + } + set + { + _group.Bounds.Left = value; + } + } + public double Top + { + get + { + return _group.Bounds.Top; + } + set + { + _group.Bounds.Top = value; + } + } + public double Width + { + get + { + return LeftMargin + (TextBody?.Bounds?.Width ?? 0D) + RightMargin + TextBody.Left; + } + } + public double WidthRotated + { + get + { + var radians = MathHelper.Radians(Rotation); + var sin = Math.Abs(Math.Sin(radians)); + var cos = Math.Abs(Math.Cos(radians)); + return Width * sin + Height * cos; + } + } + public double Height + { + get + { + return TopMargin + (TextBody?.Bounds.Height ?? 0d) + BottomMargin + TextBody.Top; + } + } + public double HeightWithRotation + { + get + { + var radians = MathHelper.Radians(Rotation); + var sin = Math.Abs(Math.Sin(radians)); + var cos = Math.Abs(Math.Cos(radians)); + return Width * cos + Height * sin; + } + } + public double LeftMargin + { + get { return _marginGroup.Left; } set { _marginGroup.Left = value; } + } + + public double TopMargin + { + get { return _marginGroup.Top; } + set { _marginGroup.Top = value; } + } + + public double RightMargin + { + get; set; + } + + public double BottomMargin + { + get; set; + } + + internal protected BoundingBox Parent { get; protected set; } + public double Rotation + { + get + { + return _group.Rotation; + } + set + { + _group.Rotation = value; + } + } + /// + /// Gets the actual width of the rotated textbox. + /// + /// + public double GetActualWidth() + { + return Width * Math.Abs(Math.Cos(MathHelper.Radians(Rotation))) + Height * Math.Abs(Math.Sin(MathHelper.Radians(Rotation))); + } + /// + /// Gets the actual right position of the rotated textbox. + /// + /// + public double GetActualRight() + { + return Left+GetActualWidth(); + } + /// + /// Gets the actual height of the rotated textbox. + /// + /// + public double GetActualHeight() + { + return Width * Math.Abs(Math.Sin(MathHelper.Radians(Rotation))) + Height * Math.Abs(Math.Cos(MathHelper.Radians(Rotation))); + } + /// + /// Gets the actual right position of the rotated textbox. + /// + /// + public double GetActualBottom() + { + return Top + GetActualHeight(); + } + public override void AppendRenderItems(List renderItems) + { + var rect = Rectangle; + + //As the rect item is inside the group, we set the left and right to the group and top and left on the rect to 0. + _group.Bounds.Left = Left; + _group.Bounds.Top = Top; + _group.Bounds.Width = Width; + _group.Bounds.Height = Height; + + _group.TextAnchor = TextAnchor.ToEnumString(); + renderItems.Add(_group); + rect.Top = 0; + rect.Left = 0; + + if (TextBody.AutoSize) + { + TextBody.ApplyAutoSize(); + } + + rect.Width = Width; + rect.Height = Height; + + var titleItem = new TitleRenderItem("TextBox group"); + _group.RenderItems.Add(titleItem); + //The rect shound encapse the text element, so we need to set the left depending on the text anchor. + if (TextAnchor == eTextAnchor.Middle) + { + _group.Bounds.Left += -(rect.Bounds.Width / 2); + } + else if (TextAnchor == eTextAnchor.End) + { + if (Math.Abs(Rotation) == 45) + { + const double COS45 = 0.70710678118654757; //Constant for Math.Sin(Math.PI / 4) --45 degrees + _group.Bounds.Left += -(rect.Bounds.Width * COS45); + _group.Bounds.Top += (rect.Bounds.Width * COS45); + } + else + { + _group.Bounds.Left += rect.Bounds.Height / 2; + _group.Bounds.Top += (rect.Bounds.Width); + } + } + _group.RenderItems.Add(rect); + + //The textbox should be in local-space. + //If e.g. a user changes textbody left and right, changing margin on the parent should not change the Local coordinates + //Therefore a group in-between should hold the margins + _marginGroup.Left = LeftMargin; + _marginGroup.Top = TopMargin; + + var marginTitleItem = new TitleRenderItem("TextBox Margin Group"); + _marginGroup.AddChildItem(marginTitleItem); + + _group.AddChildItem(_marginGroup); + TextBody.AppendRenderItems(_marginGroup.RenderItems); + } + /// + /// How the text is anchored. + /// + public eTextAnchor TextAnchor + { + get; + set; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/IRichTextFormatDrawing.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/IRichTextFormatDrawing.cs new file mode 100644 index 0000000000..548a9ab0ec --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/IRichTextFormatDrawing.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using System.Drawing; + +namespace EPPlus.DrawingRenderer.RenderItems.Textbox +{ + /// + /// TODO: Move this to interfaces. Only here in order to not break existing references in PDF + /// (This should be moved when IRichTextFormatSimple is moved) + /// + /// Rich text data for drawings + /// + public interface IRichTextFormatDrawing : IRichTextFormatSimple + { + public new eDrawingStrikeType StrikeType { get; set; } /*{ get { return (DrawingStrikeType)StrikeType; } set { StrikeType = (int)value; } }*/ + public new eDrawingUnderLineType UnderlineType { get; set; } + Color? HighLightColor { get; set; } + /// + /// The spacing between characters within a text run. + /// + double Spacing { get; set; } + + /// + /// +Superscript or -Subscript offset in percent + /// (default 30% Super and -25% subscript) + /// + public double Baseline { get; set; } + + //TODO: Advanced fills/Textoutline + //TODO: Effects once implemented in Epplus + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/RichTextFormatDrawing.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/RichTextFormatDrawing.cs new file mode 100644 index 0000000000..cc4df26c5f --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RichTextFormatDrawing/RichTextFormatDrawing.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; + +namespace EPPlus.DrawingRenderer.RenderItems.Textbox +{ + /// + /// Default richText data class for drawings + /// + public class RichTextFormatDrawing : RichTextFormatSimple, IRichTextFormatDrawing + { + public new eDrawingStrikeType StrikeType { get => (eDrawingStrikeType)base.StrikeType; set => base.StrikeType = (int)value; } + public new eDrawingUnderLineType UnderlineType { get => (eDrawingUnderLineType)base.UnderlineType; set => base.UnderlineType = (int)value; } + + public Color? HighLightColor { get; set; } + public double Spacing { get; set; } = 0d; + + double _baseLine = 0d; + + private bool _subScript = false; + private bool _superScript = false; + + /// + /// +Superscript or -Subscript offset in percent + /// (default 30% Super and -25% subscript) + /// + public double Baseline + { + get + { + return _baseLine; + } + set + { + if (value > 0d) + { + _superScript = true; + _subScript = false; + } + else if (value < 0d) + { + _superScript = false; + _subScript = true; + } + else + { + //When offset is 0 it is neither a sub or super script + _superScript = false; + _subScript = false; + } + + _baseLine = value; + } + } + public new bool SubScript + { + get + { + return _subScript; + } + set + { + if (value == true) + { + _superScript = false; + Baseline = -25d; + } + _subScript = value; + } + } + + public new bool SuperScript + { + get + { + return _superScript; + } + set + { + if (value == true) + { + _subScript = false; + Baseline = 30d; + } + _superScript = value; + } + } + + public RichTextFormatDrawing() : base() + { + StrikeType = eDrawingStrikeType.No; + UnderlineType = eDrawingUnderLineType.None; + } + + public RichTextFormatDrawing(string text, string fontFamily, float size, bool bold = false, bool italic = false) : base(text, fontFamily, size, bold, italic) + { + StrikeType = eDrawingStrikeType.No; + UnderlineType = eDrawingUnderLineType.None; + } + + public RichTextFormatDrawing(FontFormatBase defaultParagraphFont) + { + SetFont(defaultParagraphFont); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/TextRunRenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/TextRunRenderItem.cs new file mode 100644 index 0000000000..0b04d4f66b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/TextRunRenderItem.cs @@ -0,0 +1,227 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.Textbox; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using System.Drawing; +using System.Text.RegularExpressions; + +namespace EPPlus.Export.ImageRenderer.RenderItems.Shared +{ + /// + /// Linestyle + /// + public enum eDrawingUnderLineType + { + /// + /// Dashed + /// + Dash, + /// + /// Dashed, Thicker + /// + DashHeavy, + /// + /// Dashed Long + /// + DashLong, + /// + /// Long Dashed, Thicker + /// + DashLongHeavy, + /// + /// Double lines with normal thickness + /// + Double, + /// + /// Dot Dash + /// + DotDash, + /// + /// Dot Dash, Thicker + /// + DotDashHeavy, + /// + /// Dot Dot Dash + /// + DotDotDash, + /// + /// Dot Dot Dash, Thicker + /// + DotDotDashHeavy, + /// + /// Dotted + /// + Dotted, + /// + /// Dotted, Thicker + /// + DottedHeavy, + /// + /// Single line, Thicker + /// + Heavy, + /// + /// No underline + /// + None, + /// + /// Single line + /// + Single, + /// + /// A single wavy line + /// + Wavy, + /// + /// A double wavy line + /// + WavyDbl, + /// + /// A single wavy line, Thicker + /// + WavyHeavy, + /// + /// Underline just the words and not the spaces between them + /// + Words + } + /// + /// BulletType of font strike + /// + public enum eDrawingStrikeType + { + /// + /// Double-lined font strike + /// + Double, + /// + /// No font strike + /// + No, + /// + /// Single-lined font strike + /// + Single + } + public abstract class TextRunRenderItem : RenderItem + { + public override RenderItemType Type => RenderItemType.TextRun; + + public int OriginalRtIdx { get; private set; } = -1; + + protected string _originalText; + public string _currentText { get; protected set; } + + public IFontFormatBase _measurementFont { get; internal protected set; } + protected bool _isFirstInParagraph; + + public double FontSizeInPixels { get; protected set; } + + public List Lines { get; set; } + + protected internal bool _isItalic = false; + protected internal bool _isBold = false; + protected internal eDrawingUnderLineType _underLineType = eDrawingUnderLineType.None; + protected internal eDrawingStrikeType _strikeType = eDrawingStrikeType.No; + protected internal Color _underlineColor; + protected internal double _baseline; + + public double YPosition { get; set; } + public double ClippingHeight { get; protected set; } = double.NaN; + public TextRunRenderItem(BoundingBox parent) : base(parent) + { + Bounds.Name = "TextRun"; + } + + public TextRunRenderItem(BoundingBox parent, string text, int origRtIdx) : base(parent) + { + Bounds.Name = "TextRun"; + _currentText = text; + OriginalRtIdx = origRtIdx; + } + + public void ImportFontData(IFontFormatBase font) + { + InitializeBase(font); + } + + public void ImportRichTextData(IRichTextFormatSimple rt) + { + InitializeBase(rt); + FillColor = "#" + rt.FontColor.To6CharHexStringImage(); + _underLineType = (int)rt.UnderlineType == -1 ? eDrawingUnderLineType.None : (eDrawingUnderLineType)rt.UnderlineType; + _underlineColor = rt.UnderlineColor; + } + + public void ImportRichTextData(IRichTextFormatDrawing rt) + { + InitializeBase(rt); + FillColor = "#" + rt.FontColor.To6CharHexStringImage(); + _baseline = rt.Baseline; + _strikeType = (int)rt.StrikeType == -1 ? eDrawingStrikeType.No : rt.StrikeType; + _underLineType = (int)rt.UnderlineType == -1 ? eDrawingUnderLineType.None : rt.UnderlineType; + } + + internal protected void InitializeBase(IFontFormatBase font) + { + //Should be ascent-only? + Bounds.Height = font.Size; + FontSizeInPixels = ((double)font.Size).PointToPixel(true); + _measurementFont = font; + } + + /// + /// Initialization for the two lower constructors + /// Not a Initialize() method since compiler warns of un-initalized variables if you do. + /// + /// + /// + /// + /// + private TextRunRenderItem(BoundingBox parent, string origText, string currentText, IFontFormatBase font) : base(parent) + { + Bounds.Name = "TextRun"; + + //possibly no longer neccesary + _originalText = origText; + + _currentText = currentText; + + //Should be ascent-only? + Bounds.Height = font.Size; + + //Possibly no longer neccesary + Lines = Regex.Split(_currentText, "\r\n|\r|\n").ToList(); + + FontSizeInPixels = ((double)font.Size).PointToPixel(true); + + _measurementFont = font; + _isFirstInParagraph = true; + } + + public TextRunRenderItem(BoundingBox parent, IFontFormatBase font, string displayText) + : this(parent, displayText, displayText, font) + { + ////Dash is default but we know there is no underline in our input here + //_underLineType = UnderLineType.None; + } + public TextRunRenderItem(BoundingBox parent, string text, IFontFormatBase font, string displayText) + : this(parent, text, string.IsNullOrEmpty(displayText) ? text : displayText, font) + { + } + + internal protected void CalculateClippingHeightFromTextBodyParent() + { + //To get clipping height we need to get the textbody bounds + if (Bounds.Parent != null && Bounds.Parent.Parent != null && Bounds.Parent.Parent.Parent != null) + { + ClippingHeight = Bounds.Parent.Parent.Parent.Position.Y + Bounds.Parent.Parent.Parent.Size.Y; + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer/RenderItems/TitleItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/TitleItem.cs new file mode 100644 index 0000000000..d634505ae1 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/RenderItems/TitleItem.cs @@ -0,0 +1,15 @@ +namespace EPPlus.DrawingRenderer.RenderItems +{ + public class TitleRenderItem : RenderItem + { + public string Title { get; private set; } + + public TitleRenderItem(string titleName) : base() + { + Title = titleName; + } + + public override RenderItemType Type => RenderItemType.CommentTitle; + + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ArcTo.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ArcTo.cs new file mode 100644 index 0000000000..a102737084 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ArcTo.cs @@ -0,0 +1,128 @@ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ArcTo : PathsBase + { + public ArcTo(XmlReader xr) + { + if (long.TryParse(xr.GetAttribute("hR"), out var hrv)) + { + HeightRadius = hrv; + } + else + { + HeightRadiusName = xr.GetAttribute("hR"); + } + + if (long.TryParse(xr.GetAttribute("wR"), out var wrv)) + { + WidthRadius = wrv; + } + else + { + WidthRadiusName = xr.GetAttribute("wR"); + } + + if (long.TryParse(xr.GetAttribute("swAng"), out var swAng)) + { + SwingAngle = swAng; + } + else + { + SwingAngleName = xr.GetAttribute("swAng"); + } + + if (long.TryParse(xr.GetAttribute("stAng"), out var stAng)) + { + StartAngle = stAng; + } + else + { + StartAngleName = xr.GetAttribute("stAng"); + } + } + public ArcTo(XmlElement e) + { + if (long.TryParse(e.GetAttribute("hR"), out var hrv)) + { + HeightRadius = hrv; + } + else + { + HeightRadiusName = e.GetAttribute("hR"); + } + + if (long.TryParse(e.GetAttribute("wR"), out var wrv)) + { + WidthRadius = wrv; + } + else + { + WidthRadiusName = e.GetAttribute("wR"); + } + + if (long.TryParse(e.GetAttribute("swAng"), out var swAng)) + { + SwingAngle = swAng; + } + else + { + SwingAngleName = e.GetAttribute("swAng"); + } + + if (long.TryParse(e.GetAttribute("stAng"), out var stAng)) + { + StartAngle = stAng; + } + else + { + StartAngleName = e.GetAttribute("stAng"); + } + } + public override PathDrawingType Type => PathDrawingType.ArcTo; + public double? HeightRadius { get; set; } + public double? StartAngle { get; set; } + public double? SwingAngle { get; set; } + public double? WidthRadius { get; set; } + public string HeightRadiusName { get; set; } + public string StartAngleName { get; set; } + public string SwingAngleName { get; set; } + public string WidthRadiusName { get; set; } + private ArcTo() + { + + } + internal override PathsBase Clone() + { + return new ArcTo() + { + HeightRadius = HeightRadius, + StartAngle = StartAngle, + SwingAngle = SwingAngle, + WidthRadius = WidthRadius, + HeightRadiusName = HeightRadiusName, + StartAngleName = StartAngleName, + SwingAngleName = SwingAngleName, + WidthRadiusName = WidthRadiusName + }; + } + double _endX, _endY; + public void SetEndCoordinates(double x, double y) + { + _endX = x; + _endY = y; + } + public override void TranslateCoordiantesToPointsAndDegrees(double coordinateRatio, double angleRatio) + { + HeightRadius /= coordinateRatio; + WidthRadius /= coordinateRatio; + StartAngle /= angleRatio; + SwingAngle /= angleRatio; + _endX = _endX / coordinateRatio; + _endY = _endY / coordinateRatio; + } + public override double EndX => _endX; + public override double EndY => _endY; + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ClosePath.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ClosePath.cs new file mode 100644 index 0000000000..9f7c21ed29 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ClosePath.cs @@ -0,0 +1,20 @@ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ClosePath : PathsBase + { + public ClosePath() + { + + } + public override PathDrawingType Type => PathDrawingType.Close; + internal override PathsBase Clone() + { + return new ClosePath(); + } + public override double EndX => double.MinValue; + public override double EndY => double.MinValue; + public override void TranslateCoordiantesToPointsAndDegrees(double coordinateRatio, double angleRatio) + { + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/CubicBezerTo.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/CubicBezerTo.cs new file mode 100644 index 0000000000..704c9c9511 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/CubicBezerTo.cs @@ -0,0 +1,26 @@ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class CubicBezerTo : PathWithCoordinates + { + public CubicBezerTo(CubicBezerTo clone) : base(clone) + { + + } + public CubicBezerTo(XmlReader xr) : base(xr) + { + + } + public CubicBezerTo(XmlElement e) : base(e) + { + + } + + public override PathDrawingType Type => PathDrawingType.CubicBezierTo; + internal override PathsBase Clone() + { + return new CubicBezerTo(this); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawCoordinate.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawCoordinate.cs new file mode 100644 index 0000000000..813524a10c --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawCoordinate.cs @@ -0,0 +1,40 @@ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class DrawCoordinate + { + public DrawCoordinate(DrawCoordinate c) + { + X = c.X; + Y = c.Y; + XName = c.XName; + YName = c.YName; + } + + public DrawCoordinate(object x, object y) + { + if (x is long xl) + { + X = xl; + } + else + { + XName = x.ToString(); + X = null; + } + if (y is long yl) + { + Y = yl; + } + else + { + YName = y.ToString(); + Y = null; + } + + } + public double? X { get; set; } + public double? Y { get; set; } + public string XName { get; set; } + public string YName { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawingPath.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawingPath.cs new file mode 100644 index 0000000000..e9c3e47845 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/DrawingPath.cs @@ -0,0 +1,117 @@ +using EPPlus.DrawingRenderer.Utils; +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class DrawingPath + { + public DrawingPath(DrawingPath clone) + { + Width = clone.Width; + Height = clone.Height; + Fill = clone.Fill; + Stroke = clone.Stroke; + ExtrusionOk = clone.ExtrusionOk; + foreach (var p in clone.Paths) + { + Paths.Add(p.Clone()); + } + } + public DrawingPath(XmlReader xr) + { + Width = ConvertUtil.GetValueLongNull(xr.GetAttribute("w")); + Height = ConvertUtil.GetValueLongNull(xr.GetAttribute("h")); + Fill = GetFill(xr.GetAttribute("fill")); + Stroke = ConvertUtil.ToBooleanString(xr.GetAttribute("stroke"), true); + ExtrusionOk = ConvertUtil.ToBooleanString(xr.GetAttribute("extrusionOk"), false); + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element) + { + switch (xr.LocalName) + { + case "moveTo": + Paths.Add(new MoveTo(xr)); + break; + case "lnTo": + Paths.Add(new LineTo(xr)); + break; + case "cubicBezTo": + Paths.Add(new CubicBezerTo(xr)); + break; + case "quadBezTo": + Paths.Add(new QuadBezerTo(xr)); + break; + case "arcTo": + Paths.Add(new ArcTo(xr)); + break; + case "close": + Paths.Add(new ClosePath()); + break; + } + } + else if (xr.LocalName == "path" && xr.NodeType == XmlNodeType.EndElement) + { + break; + } + } + } + + public DrawingPath(XmlElement topNode, XmlNamespaceManager nsm) + { + Width = int.Parse(topNode.GetAttribute("w")); + Height = int.Parse(topNode.GetAttribute("h")); + Fill = GetFill(topNode.GetAttribute("fill")); + Stroke = ConvertUtil.ToBooleanString(topNode.GetAttribute("stroke"), true); + ExtrusionOk = ConvertUtil.ToBooleanString(topNode.GetAttribute("extrusionOk"), true); + foreach (var child in topNode.ChildNodes) + { + if (child is XmlElement e) + { + switch (e.LocalName) + { + case "moveTo": + Paths.Add(new MoveTo(e)); + break; + case "lnTo": + Paths.Add(new LineTo(e)); + break; + case "cubicBezTo": + Paths.Add(new CubicBezerTo(e)); + break; + case "quadBezTo": + Paths.Add(new CubicBezerTo(e)); + break; + case "arcTo": + Paths.Add(new ArcTo(e)); + break; + case "close": + Paths.Add(new ClosePath()); + break; + } + } + } + } + + private PathFillMode GetFill(string s) + { + if (string.IsNullOrEmpty(s) == false) + { + return (PathFillMode)Enum.Parse(typeof(PathFillMode), s, true); + } + return PathFillMode.Norm; + } + + public DrawingPath Clone() => new DrawingPath(this); + + public bool Stroke { get; set; } + public bool ExtrusionOk { get; set; } + public PathFillMode Fill { get; set; } + public double? Width { get; set; } + public double? Height { get; set; } + public List Paths { get; set; } = new List(); + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/LineTo.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/LineTo.cs new file mode 100644 index 0000000000..d8ed12dcfa --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/LineTo.cs @@ -0,0 +1,27 @@ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class LineTo : PathWithCoordinates + { + public LineTo(LineTo clone) : base(clone) + { + + } + public LineTo(XmlReader xr) : base(xr) + { + + } + + public LineTo(XmlElement e) : base(e) + { + + } + public override PathDrawingType Type => PathDrawingType.LineTo; + public DrawCoordinate Coordinate { get; set; } + internal override PathsBase Clone() + { + return new LineTo(this); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/MoveTo.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/MoveTo.cs new file mode 100644 index 0000000000..035229333c --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/MoveTo.cs @@ -0,0 +1,25 @@ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class MoveTo : PathWithCoordinates + { + public MoveTo(MoveTo clone) : base(clone) + { + + } + public MoveTo(XmlElement e) : base(e) + { + } + public MoveTo(XmlReader xr) : base(xr) + { + } + public override PathDrawingType Type => PathDrawingType.MoveTo; + public DrawCoordinate Coordinate { get; set; } + + internal override PathsBase Clone() + { + return new MoveTo(this); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathWithCoordinates.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathWithCoordinates.cs new file mode 100644 index 0000000000..3e114aa706 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathWithCoordinates.cs @@ -0,0 +1,64 @@ +using EPPlus.DrawingRenderer.Utils; +using System.Globalization; +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public abstract class PathWithCoordinates : PathsBase + { + protected PathWithCoordinates(XmlElement e) + { + foreach (var cn in e.ChildNodes) + { + if (cn is XmlElement ce && ce.LocalName == "pt") + { + Coordinates.Add(new DrawCoordinate(GetNameOrNumber(ce.GetAttribute("x")), GetNameOrNumber(ce.GetAttribute("y")))); + } + } + } + + private object GetNameOrNumber(string s) + { + if (long.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var l)) + { + return l; + } + return s; + } + + protected PathWithCoordinates(XmlReader xr) + { + var name = xr.LocalName; + while (xr.Read()) + { + if (xr.LocalName == "pt" && xr.NodeType == XmlNodeType.Element) + { + Coordinates.Add(new DrawCoordinate(GetNameOrNumber(xr.GetAttribute("x")), GetNameOrNumber(xr.GetAttribute("y")))); + } + else if (xr.IsEndElementWithName(name)) + { + break; + } + } + } + + protected PathWithCoordinates(PathWithCoordinates clone) + { + foreach (var c in clone.Coordinates) + { + Coordinates.Add(new DrawCoordinate(c)); + } + } + public List Coordinates { get; set; } = new List(); + public override void TranslateCoordiantesToPointsAndDegrees(double coordinateRatio, double angleRatio) + { + foreach (var c in Coordinates) + { + c.X /= coordinateRatio; + c.Y /= coordinateRatio; + } + } + public override double EndX => Coordinates.Count > 0D ? Coordinates[Coordinates.Count - 1].X.Value : 0D; + public override double EndY => Coordinates.Count > 0D ? Coordinates[Coordinates.Count - 1].Y.Value : 0D; + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathsBase.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathsBase.cs new file mode 100644 index 0000000000..f7b591cd6f --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PathsBase.cs @@ -0,0 +1,12 @@ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public abstract class PathsBase + { + public abstract PathDrawingType Type { get; } + + internal abstract PathsBase Clone(); + public abstract double EndX { get; } + public abstract double EndY { get; } + public abstract void TranslateCoordiantesToPointsAndDegrees(double coordinateRatio, double angleRatio); + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefinition.Sync.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefinition.Sync.cs new file mode 100644 index 0000000000..5449c06b88 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefinition.Sync.cs @@ -0,0 +1,253 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.ShapeDefinitions; +using EPPlus.DrawingRenderer.Utils; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public partial class PresetShapeDefinitions + { + public static void LoadPresetShapeDefinitionFromXml() + { + var xmlFile = Directory.GetCurrentDirectory() + "\\resource\\presetShapeDefinitions.xml"; + + try + { + var ms = new MemoryStream(File.ReadAllBytes(xmlFile)); +#if NET35 + var xr = XmlReader.Create(ms, new XmlReaderSettings() + { + ProhibitDtd=true, + IgnoreWhitespace = true + }); +#else + var xr = XmlReader.Create(ms, new XmlReaderSettings() + { + DtdProcessing = DtdProcessing.Prohibit, + IgnoreWhitespace = true, + Async = true + }); +#endif + + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element) + { + if (xr.LocalName != "presetShapeDefinitons") + { + var item = LoadPresetShapeDefinition(xr); + _shapeDefinitions.Add(item.Style, item); + } + } + } + } + catch (Exception ex) + { + throw (new IOException("Cannot preset shape definitions file:presetShapeDefinitions.xml", ex)); + } + } + + public static bool LoadPresetShapeDefinitionFromXmlTriangle() + { + _shapeDefinitions = new Dictionary(); + + var xmlFile = Directory.GetCurrentDirectory() + "\\resource\\triangleOnly.xml"; + var fs = new FileStream(xmlFile, FileMode.Open, FileAccess.Read); +#if NET35 + var xr = XmlReader.Create(fs, new XmlReaderSettings() + { + ProhibitDtd=true, + IgnoreWhitespace = true + }); +#else + var xr = XmlReader.Create(fs, new XmlReaderSettings() + { + DtdProcessing = DtdProcessing.Prohibit, + IgnoreWhitespace = true, + Async = true + }); +#endif + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element) + { + if (xr.LocalName == "triangle" && xr.NodeType != XmlNodeType.EndElement) + { + var item = LoadPresetShapeDefinition(xr); + _shapeDefinitions.Add(item.Style, item); + } + } + } + return true; + } + + private static ShapeDefinition LoadPresetShapeDefinition(XmlReader xr) + { + var style = xr.LocalName.ToEnum(); + if (!style.HasValue) throw new InvalidOperationException(); + var psd = new ShapeDefinition + { + Style = style.Value, + }; + LoadFromXml(psd, xr); + return psd; + } + + private static void LoadFromXml(ShapeDefinition psd, XmlReader xr) + { + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element) + { + switch (xr.LocalName) + { + case "avLst": + psd.ShapeAdjustValues = LoadShapeGuides(xr); + break; + case "gdLst": + psd.ShapeGuides = LoadShapeGuides(xr); + break; + case "ahLst": + psd.ShapeAdjustHandles = LoadAdjustHandle(xr); + break; + case "cxnLst": + psd.ShapeConnectionSite = LoadConnectionLst(xr); + break; + case "rect": + psd.TextBoxRect = LoadRect(xr); + break; + case "pathLst": + psd.ShapePaths = LoadShapePaths(xr); + break; + } + } + else if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName.Equals(psd.Style.ToString(), StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + } + } + + private static TextBoxRect LoadRect(XmlReader xr) + { + // < rect l = "l" t = "y1" r = "x4" b = "b" xmlns = "http://schemas.openxmlformats.org/drawingml/2006/main" /> + var rect = new TextBoxRect() + { + TopName = xr.GetAttribute("t"), + BottomName = xr.GetAttribute("b"), + LeftName = xr.GetAttribute("l"), + RightName = xr.GetAttribute("r") + }; + + return rect; + } + + private static List LoadConnectionLst(XmlReader xr) + { + var shapeConnectionSite = new List(); + + while (xr.Read() && (xr.NodeType != XmlNodeType.EndElement && xr.LocalName != "cxnLst")) + { + var newConnection = new ShapeConnectionSite(); + + var attrStr = xr.GetAttribute("ang"); + + newConnection.Angle = xr.GetAttribute("ang"); + xr.Read(); + + newConnection.PositionCoordinate = new ShapePositionCoordinate() { X = xr.GetAttribute("x"), Y = xr.GetAttribute("y") }; + + shapeConnectionSite.Add(newConnection); + xr.Read(); + + if (xr.LocalName == "cxnLst" && xr.NodeType == XmlNodeType.EndElement) + { + break; + } + } + + return shapeConnectionSite; + } + + private static List LoadAdjustHandle(XmlReader xr) + { + var l = new List(); + var name = xr.LocalName; + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element) + { + switch (xr.LocalName) + { + case "ahXY": + l.Add(ShapeAdjustHandleBase.CreateXy(xr)); + break; + case "ahPolar": + l.Add(ShapeAdjustHandleBase.CreatePolar(xr)); + break; + case "pos": + l[l.Count - 1].PositionCoordinate = new ShapePositionCoordinate() { X = xr.GetAttribute("x"), Y = xr.GetAttribute("y") }; + break; + } + } + else if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName == name) + { + break; + } + } + return l; + } + + private static List LoadShapeGuides(XmlReader xr) + { + var l = new List(); + var name = xr.LocalName; + while (xr.Read()) + { + if (xr.NodeType == XmlNodeType.Element && xr.LocalName == "gd") + { + l.Add(new ShapeGuide() { Name = xr.GetAttribute("name"), Formula = xr.GetAttribute("fmla") }); + } + + if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName == name) + { + break; + } + } + return l; + } + + + private static List LoadShapePaths(XmlReader xr) + { + var list = new List(); + while (xr.Read()) + { + if (xr.LocalName == "path" && xr.NodeType == XmlNodeType.Element) + { + list.Add(new DrawingPath(xr)); + } + else if (xr.IsEndElementWithName("pathLst")) + { + break; + } + } + return list; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefiniton.Async.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefiniton.Async.cs new file mode 100644 index 0000000000..a131a20e1a --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/PresetShapeDefiniton.Async.cs @@ -0,0 +1,256 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.ShapeDefinitions; +using System; +using System.Collections.Generic; +using System.IO; + +#if !NET35 +//using System.Reflection.Metadata.Ecma335; +using System.Threading.Tasks; +//using System.Windows.Markup; +#endif +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public partial class PresetShapeDefinitions + { + static object _syncRoot=new object(); + static Dictionary _shapeDefinitions=null; + public static Dictionary ShapeDefinitions + { + get + { + lock (_syncRoot) + { + if (_shapeDefinitions == null) + { + _shapeDefinitions = new Dictionary(); +#if NET35 + LoadPresetShapeDefinitionFromXml(); +#else + Task.Run(() => LoadPresetShapeDefinitionFromXmlAsync()).Wait(); +#endif + + } + return _shapeDefinitions; + } + } + } + +#if !NET35 + public static async Task LoadPresetShapeDefinitionFromXmlAsync() + { + var xmlFile = Directory.GetCurrentDirectory() + "\\resource\\presetShapeDefinitions.xml"; + + try + { + var ms=new MemoryStream(File.ReadAllBytes(xmlFile)); + var xr = XmlReader.Create(ms, new XmlReaderSettings() + { + DtdProcessing = DtdProcessing.Prohibit, + IgnoreWhitespace = true, + Async = true + }); + + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element) + { + if (xr.LocalName != "presetShapeDefinitons") + { + var item = await LoadPresetShapeDefinitionAsync(xr); + _shapeDefinitions.Add(item.Style, item); + } + } + } + } + catch(Exception ex) + { + throw (new IOException("Cannot preset shape definitions file:presetShapeDefinitions.xml", ex)); + } + } + + public static async Task LoadPresetShapeDefinitionFromXmlAsyncTriangle() + { + _shapeDefinitions = new Dictionary(); + + var xmlFile = Directory.GetCurrentDirectory() + "\\resource\\triangleOnly.xml"; + var fs = new FileStream(xmlFile, FileMode.Open, FileAccess.Read); + var xr = XmlReader.Create(fs, new XmlReaderSettings() + { + DtdProcessing = DtdProcessing.Prohibit, + IgnoreWhitespace = true, + Async = true + }); + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element) + { + if (xr.LocalName == "triangle" && xr.NodeType != XmlNodeType.EndElement) + { + var item = await LoadPresetShapeDefinitionAsync(xr); + _shapeDefinitions.Add(item.Style, item); + } + } + } + return true; + } + + private static async Task LoadPresetShapeDefinitionAsync(XmlReader xr) + { + if (Enum.TryParse(xr.LocalName, true, out var style)) + { + var psd = new ShapeDefinition() + { + Style = style + }; + await LoadFromXmlAsync(psd, xr); + return psd; + } + throw new InvalidOperationException(); + } + private static async Task LoadFromXmlAsync(ShapeDefinition psd, XmlReader xr) + { + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element) + { + switch (xr.LocalName) + { + case "avLst": + psd.ShapeAdjustValues = await LoadShapeGuidesAsync(xr); + break; + case "gdLst": + psd.ShapeGuides = await LoadShapeGuidesAsync(xr); + break; + case "ahLst": + psd.ShapeAdjustHandles = await LoadAdjustHandleAsync(xr); + break; + case "cxnLst": + psd.ShapeConnectionSite = await LoadConnectionLstAsync(xr); + break; + case "rect": + psd.TextBoxRect = new TextBoxRect() { TopName = xr.GetAttribute("t"), BottomName = xr.GetAttribute("b"), LeftName = xr.GetAttribute("l"), RightName = xr.GetAttribute("r") }; + break; + case "pathLst": + psd.ShapePaths = LoadShapePaths(xr); + break; + } + } + else if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName.Equals(psd.Style.ToString(), StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + } + } + + private static async Task LoadRectAsync(XmlReader xr) + { + TextBoxRect rect; + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element && xr.LocalName == "rect") + { + rect = new TextBoxRect() + { + TopName = xr.GetAttribute("t"), + BottomName = xr.GetAttribute("b"), + LeftName = xr.GetAttribute("l"), + RightName = xr.GetAttribute("r") + }; + return rect; + } + } + return null; + } + + private static async Task> LoadConnectionLstAsync(XmlReader xr) + { + var shapeConnectionSite = new List(); + + while (await xr.ReadAsync() && (xr.NodeType != XmlNodeType.EndElement && xr.LocalName != "cxnLst")) + { + var newConnection = new ShapeConnectionSite(); + + var attrStr = xr.GetAttribute("ang"); + + newConnection.Angle = xr.GetAttribute("ang"); + await xr.ReadAsync(); + + newConnection.PositionCoordinate = new ShapePositionCoordinate() { X = xr.GetAttribute("x"), Y = xr.GetAttribute("y") }; + + shapeConnectionSite.Add(newConnection); + await xr.ReadAsync(); + + if (xr.LocalName == "cxnLst" && xr.NodeType == XmlNodeType.EndElement) + { + break; + } + } + + return shapeConnectionSite; + } + + private static async Task> LoadAdjustHandleAsync(XmlReader xr) + { + var l = new List(); + var name = xr.LocalName; + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element) + { + switch (xr.LocalName) + { + case "ahXY": + l.Add(ShapeAdjustHandleBase.CreateXy(xr)); + break; + case "ahPolar": + l.Add(ShapeAdjustHandleBase.CreatePolar(xr)); + break; + case "pos": + l[l.Count - 1].PositionCoordinate = new ShapePositionCoordinate() { X = xr.GetAttribute("x"), Y = xr.GetAttribute("y") }; + break; + } + } + else if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName == name) + { + break; + } + } + return l; + } + + private static async Task> LoadShapeGuidesAsync(XmlReader xr) + { + var l = new List(); + var name = xr.LocalName; + while (await xr.ReadAsync()) + { + if (xr.NodeType == XmlNodeType.Element && xr.LocalName == "gd") + { + l.Add(new ShapeGuide() { Name = xr.GetAttribute("name"), Formula = xr.GetAttribute("fmla") }); + } + + if (xr.NodeType == XmlNodeType.EndElement && xr.LocalName == name) + { + break; + } + } + return l; + } +#endif + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/QuadBezerTo.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/QuadBezerTo.cs new file mode 100644 index 0000000000..3a4f6156c2 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/QuadBezerTo.cs @@ -0,0 +1,26 @@ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class QuadBezerTo : PathWithCoordinates + { + public QuadBezerTo(QuadBezerTo clone) : base(clone) + { + + } + public QuadBezerTo(XmlReader xr) : base(xr) + { + + } + public QuadBezerTo(XmlElement e) : base(e) + { + + } + public override PathDrawingType Type => PathDrawingType.QuadBezierTo; + internal override PathsBase Clone() + { + return new QuadBezerTo(this); + } + + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandle.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandle.cs new file mode 100644 index 0000000000..8287241b75 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandle.cs @@ -0,0 +1,49 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Xml; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + + public abstract class ShapeAdjustHandleBase + { + public abstract ShapeAdjustHandleType AhType { get; } + public ShapePositionCoordinate PositionCoordinate { get; set; } + public static ShapeAdjustHandleXY CreateXy(XmlReader xr) + { + return new ShapeAdjustHandleXY() + { + HorizontalAdjustmentGuide = xr.GetAttribute("gdRefX"), + VerticalAdjustmentGuide = xr.GetAttribute("gdRefY"), + MinimumHorizontalAdjustment = xr.GetAttribute("minX"), + MaximumHorizontalAdjustment = xr.GetAttribute("minY"), + MinimumVerticalAdjustment = xr.GetAttribute("maxX"), + MaximumVerticalAdjustment = xr.GetAttribute("maxY"), + }; + } + public static ShapeAdjustHandlePolar CreatePolar(XmlReader xr) + { + return new ShapeAdjustHandlePolar() + { + AngleAdjustmentGuide = xr.GetAttribute("gdRefAng"), + RadialAdjustmentGuide = xr.GetAttribute("gdRefR"), + MinimumAngleAdjustment = xr.GetAttribute("minAng"), + MinimumRadialAdjustment = xr.GetAttribute("minR"), + MaximumAngleAdjustment = xr.GetAttribute("maxAng"), + MaximumRadialAdjustment = xr.GetAttribute("maxR"), + }; + } + + public abstract ShapeAdjustHandleBase Clone(); + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandlePolar.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandlePolar.cs new file mode 100644 index 0000000000..93503e73a4 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandlePolar.cs @@ -0,0 +1,39 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ShapeAdjustHandlePolar : ShapeAdjustHandleBase + { + public override ShapeAdjustHandleType AhType => ShapeAdjustHandleType.Polar; + public string AngleAdjustmentGuide { get; set; } + public string RadialAdjustmentGuide { get; set; } + public object MaximumAngleAdjustment { get; set; } + public object MaximumRadialAdjustment { get; set; } + public object MinimumAngleAdjustment { get; set; } + public object MinimumRadialAdjustment { get; set; } + public override ShapeAdjustHandleBase Clone() + { + return new ShapeAdjustHandlePolar() + { + AngleAdjustmentGuide = AngleAdjustmentGuide, + RadialAdjustmentGuide = RadialAdjustmentGuide, + MaximumAngleAdjustment = MaximumAngleAdjustment, + MinimumAngleAdjustment = MinimumAngleAdjustment, + MaximumRadialAdjustment = MaximumRadialAdjustment, + MinimumRadialAdjustment = MinimumRadialAdjustment, + }; + } + + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleType.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleType.cs new file mode 100644 index 0000000000..d01eeeeff6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleType.cs @@ -0,0 +1,20 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public enum ShapeAdjustHandleType + { + XY, + Polar, + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleXY.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleXY.cs new file mode 100644 index 0000000000..3bfb9e6928 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeAdjustHandleXY.cs @@ -0,0 +1,65 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ShapeAdjustHandleXY : ShapeAdjustHandleBase + { + public override ShapeAdjustHandleType AhType => ShapeAdjustHandleType.XY; + + /// + ///Specifies the name of the guide that is updated with the adjustment x position from this adjust handle. + ///The possible values for this attribute are defined by the ST_GeomGuideName simple type (§20.1.10.28). + /// + public string HorizontalAdjustmentGuide { get; set; } + /// + /// Specifies the name of the guide that is updated with the adjustment y position from this adjust handle. + /// + public string VerticalAdjustmentGuide { get; set; } + /// + /// Specifies the minimum horizontal position that is allowed for this adjustment handle. + /// If this attribute is omitted, then it is assumed that this adjust handle cannot move in the x direction. + /// That is the maxX and minX are equal. + /// + public object MinimumHorizontalAdjustment{ get; set; } + /// + /// Specifies the maximum horizontal position that is allowed for this adjustment handle. + /// If this attribute is omitted, then it is assumed that this adjust handle cannot move in the x direction. + /// That is the maxX and minX are equal. + /// + public object MaximumHorizontalAdjustment { get; set; } + /// + /// Specifies the minimum vertical position that is allowed for this adjustment handle. + /// If this attribute is omitted, then it is assumed that this adjust handle cannot move in the y direction.That is the maxY and minY are equal. + /// + public object MinimumVerticalAdjustment { get; set; } + /// + /// Specifies the minimum vertical position that is allowed for this adjustment handle. + /// If this attribute is omitted, then it is assumed that this adjust handle cannot move in the y direction. + /// That is the maxY and minY are equal. + /// + public object MaximumVerticalAdjustment { get; set; } + public override ShapeAdjustHandleBase Clone() + { + return new ShapeAdjustHandleXY() + { + HorizontalAdjustmentGuide = HorizontalAdjustmentGuide, + VerticalAdjustmentGuide = VerticalAdjustmentGuide, + MinimumHorizontalAdjustment = MinimumHorizontalAdjustment, + MaximumHorizontalAdjustment = MaximumHorizontalAdjustment, + MinimumVerticalAdjustment = MinimumVerticalAdjustment, + MaximumVerticalAdjustment = MaximumVerticalAdjustment, + }; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeConnectionSite.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeConnectionSite.cs new file mode 100644 index 0000000000..f5a0d3b403 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeConnectionSite.cs @@ -0,0 +1,21 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ShapeConnectionSite + { + public object Angle { get; set; } + public ShapePositionCoordinate PositionCoordinate { get; set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs new file mode 100644 index 0000000000..8e9885c35a --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs @@ -0,0 +1,512 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.Utils; +using System.Diagnostics; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + [DebuggerDisplay("{Style}")] + public class ShapeDefinition + { + public Dictionary _calculatedValues = new Dictionary(); + + public ShapeDefinition() + { + + } + /// + /// Clone constructor + /// + /// The original to clone from + protected ShapeDefinition(ShapeDefinition original) + { + Style=original.Style; + if (original.ShapeAdjustValues != null) + { + ShapeAdjustValues = new List(); + foreach (var av in original.ShapeAdjustValues) + { + ShapeAdjustValues.Add(av.Clone()); + } + } + if (original.ShapeGuides != null) + { + ShapeGuides = new List(); + foreach (var g in original.ShapeGuides) + { + ShapeGuides.Add(g.Clone()); + } + } + + if (original.ShapeAdjustHandles!=null) + { + ShapeAdjustHandles = new List(); + foreach (var ah in original.ShapeAdjustHandles) + { + ShapeAdjustHandles.Add(ah.Clone()); + } + } + + TextBoxRect = original.TextBoxRect?.Clone(); + + ShapePaths = new List(); + foreach (var p in original.ShapePaths) + { + ShapePaths.Add(p.Clone()); + } + } + + + public ShapeStyle Style { get; set; } + /// + /// avLst + /// + public List ShapeAdjustValues { get; set; } + /// + /// gdLst + /// + public List ShapeGuides { get; set; } + /// + /// ahLst + /// + public List ShapeAdjustHandles { get; set; } + //cxnLst + public List ShapeConnectionSite { get; set; } + //rect + /// + /// The rectangle for the text inside the shape. + /// + public TextBoxRect TextBoxRect { get; set; } + //pathLst + /// + /// Paths to draw the shape + /// + public List ShapePaths { get; set; } + + + //private object GetValueOfNameOrCalculateValue(object value) + //{ + // if (value is string s && _calculatedValues.ContainsKey(s)) + // { + // return _calculatedValues[s]; + // } + // return value; + //} + public void Calculate(double width, double height, bool textAutofit, List customAdjPtsNames, List customAdjPts) + { + InitCalculatedValues(width, height); + + if (ShapeAdjustValues != null) + { + //if (shape.HasCustomAdjustmentPoints()) + //{ + // var names = shape.GetAdjustmentPointsNames(); + // var l = shape.GetAdjustmentPointsList(); + if (customAdjPts != null && customAdjPtsNames != null) + { + + for (int i = 0; i < ShapeAdjustValues.Count; i++) + { + _calculatedValues.Add(customAdjPtsNames[i], Convert.ToDouble(customAdjPts[i])); + } + } + else + { + foreach (var ap in ShapeAdjustValues) + { + if (string.IsNullOrEmpty(ap.Formula) == false) + { + ap.CalculatedValue = CalculateFormula(ap.Formula); + _calculatedValues.Add(ap.Name, ap.CalculatedValue); + } + } + } + } + if (ShapeGuides != null) + { + foreach (var g in ShapeGuides) + { + g.CalculatedValue = CalculateFormula(g.Formula); + + if (g.CalculatedValue == double.MaxValue || g.CalculatedValue == double.PositiveInfinity || g.CalculatedValue == double.NegativeInfinity) + { + throw new Exception($"Double overflowed during calculation of {g.Name}"); + } + + if (_calculatedValues.ContainsKey(g.Name)) + { + _calculatedValues[g.Name] = g.CalculatedValue; + } + else + { + _calculatedValues.Add(g.Name, g.CalculatedValue); + } + } + } + if (ShapeAdjustHandles != null) + { + foreach (var h in ShapeAdjustHandles) + { + switch (h.AhType) + { + case ShapeAdjustHandleType.XY: + var xyH = (ShapeAdjustHandleXY)h; + xyH.MinimumVerticalAdjustment = GetValueOfNameOrCalculateValue(xyH.MinimumVerticalAdjustment); + xyH.MaximumVerticalAdjustment = GetValueOfNameOrCalculateValue(xyH.MaximumVerticalAdjustment); + xyH.MinimumHorizontalAdjustment = GetValueOfNameOrCalculateValue(xyH.MinimumHorizontalAdjustment); + xyH.MaximumHorizontalAdjustment = GetValueOfNameOrCalculateValue(xyH.MaximumHorizontalAdjustment); + break; + case ShapeAdjustHandleType.Polar: + var polarH = (ShapeAdjustHandlePolar)h; + polarH.MinimumAngleAdjustment = GetValueOfNameOrCalculateValue(polarH.MinimumAngleAdjustment); + polarH.MaximumAngleAdjustment = GetValueOfNameOrCalculateValue(polarH.MaximumAngleAdjustment); + polarH.MinimumRadialAdjustment = GetValueOfNameOrCalculateValue(polarH.MinimumRadialAdjustment); + polarH.MaximumRadialAdjustment = GetValueOfNameOrCalculateValue(polarH.MaximumRadialAdjustment); + break; + } + } + } + + double overrideWidthRatio = 1; + double overrideHeightRatio = 1; + + if (TextBoxRect != null) + { + //if (textAutofit != eTextAutofit.ShapeAutofit) + if (textAutofit == false) + { + TextBoxRect.LeftValue = GetValue(TextBoxRect.LeftName) / Constants.EMU_PER_PIXEL; + TextBoxRect.RightValue = GetValue(TextBoxRect.RightName) / Constants.EMU_PER_PIXEL; + TextBoxRect.TopValue = GetValue(TextBoxRect.TopName) / Constants.EMU_PER_PIXEL; + TextBoxRect.BottomValue = GetValue(TextBoxRect.BottomName) / Constants.EMU_PER_PIXEL; + } + else + { + //var txt = shape.Text; + + //List txtContainers = new List(); + + ////TODO: This needs to actually iterate through the individual paragraphs/txtRuns when differing fonts/font sizes exist + ////foreach(var paragraph in shape.TextBodyItem.Paragraphs) + ////{ + //// foreach(var txtRun in paragraph.TextRuns) + //// { + //// var newContainer = new TextContainer(txt, txtRun.GetMeasureFont(), true); + //// txtContainers.Add(newContainer); + //// } + ////} + //var newContainer = new TextContainer(txt, shape.TextBodyItem.Paragraphs.FirstDefaultRunProperties.GetMeasureFont(), true); + + //var cW = newContainer.Width; + //var cH = newContainer.Height; + + //var expectedWidth = (GetValue(TextBoxRect.RightName) - GetValue(TextBoxRect.LeftName)) / (double)ExcelDrawing.EMU_PER_PIXEL; + //var expectedHeight = (GetValue(TextBoxRect.BottomName) - GetValue(TextBoxRect.TopName)) / (double)ExcelDrawing.EMU_PER_PIXEL; + + //overrideWidthRatio = cW / expectedWidth; + //overrideHeightRatio = cH / expectedHeight; + + //TextBoxRect.RightValue = cW; + //TextBoxRect.BottomValue = cH; + + //TextBoxRect.LeftValue = GetValue(TextBoxRect.LeftName) / (double)ExcelDrawing.EMU_PER_PIXEL * overrideWidthRatio; + //TextBoxRect.TopValue = GetValue(TextBoxRect.TopName) / (double)ExcelDrawing.EMU_PER_PIXEL * overrideHeightRatio; + } + } + + if (ShapePaths.Count > 0) + { + foreach (var item in ShapePaths) + { + var shapeWidth = (double)width * Constants.EMU_PER_PIXEL; + var shapeHeight = (double)height * Constants.EMU_PER_PIXEL; + + var widthRatio = item.Width.HasValue ? (double)shapeWidth / (double)item.Width : 1D; + var heightRatio = item.Height.HasValue ? (double)shapeWidth / (double)item.Height : 1D; + + widthRatio *= overrideWidthRatio; + heightRatio *= overrideHeightRatio; + + item.Width = shapeWidth; + item.Height = shapeHeight; + + foreach (var p in item.Paths) + { + switch (p.Type) + { + case PathDrawingType.Close: + break; + case PathDrawingType.ArcTo: + var arc = (ArcTo)p; + if (string.IsNullOrEmpty(arc.WidthRadiusName) == false) + { + arc.WidthRadius = _calculatedValues[arc.WidthRadiusName] * overrideWidthRatio; + } + else + { + arc.WidthRadius = (double)((arc.WidthRadius ?? 0D) * widthRatio); + } + if (string.IsNullOrEmpty(arc.HeightRadiusName) == false) + { + arc.HeightRadius = _calculatedValues[arc.HeightRadiusName] * overrideHeightRatio; + } + else + { + arc.HeightRadius = (double)((arc.HeightRadius ?? 0D) * heightRatio); + } + if (string.IsNullOrEmpty(arc.StartAngleName) == false) arc.StartAngle = _calculatedValues[arc.StartAngleName]; + if (string.IsNullOrEmpty(arc.SwingAngleName) == false) arc.SwingAngle = _calculatedValues[arc.SwingAngleName]; + break; + default: + var pb = (PathWithCoordinates)p; + for (var i = 0; i < pb.Coordinates.Count; i++) + { + var c = pb.Coordinates[i]; + if (string.IsNullOrEmpty(c.XName) == false) + { + c.X = _calculatedValues[c.XName] * overrideWidthRatio; + } + else + { + c.X = (double)((c.X ?? 0D) * widthRatio); + } + + if (string.IsNullOrEmpty(c.YName) == false) + { + c.Y = _calculatedValues[c.YName] * overrideHeightRatio; + } + else + { + c.Y = (double)((c.Y ?? 0D) * heightRatio); + } + } + break; + } + } + } + } + } + private object GetValueOfNameOrCalculateValue(object value) + { + if (value is string s && _calculatedValues.ContainsKey(s)) + { + return _calculatedValues[s]; + } + return value; + } + + private void InitCalculatedValues(double width, double height) + { + + var adjustedHeight = height; + var adjustedWidth = width; + + //Convert shape bounds from pixels to EMUs + var h = (double)(adjustedHeight * Constants.EMU_PER_PIXEL); + var w = (double)(adjustedWidth * Constants.EMU_PER_PIXEL); + + //Longest side + var ls = Math.Max(h, w); + //Shortest side + var ss = Math.Min(h, w); + + _calculatedValues = new Dictionary() + { + {"t", 0d }, + {"l", 0d }, + {"w", w }, + {"r", w }, + {"h", h }, + {"b", h }, + {"hc", w/2d }, + {"vc", h/2d }, + {"ls", ls }, + {"ss", ss }, + {"3cd4", 16200000.0d}, + {"3cd8", 8100000.0d}, + {"5cd8", 13500000.0d}, + {"7cd8", 18900000.0d}, + {"cd2", 10800000.0d}, + {"cd4", 5400000.0d}, + {"cd8", 2700000.0d}, + {"hd2", h/2d}, + {"hd3", h/3d}, + {"hd4", h/4d}, + {"hd5", h/5d}, + {"hd6", h/6d}, + {"hd8", h/8d}, + {"wd2", w/2d}, + {"wd3", w/3d}, + {"wd4", w/4d}, + {"wd5", w/5d}, + {"wd6", w/6d}, + {"wd8", w/8d}, + {"wd10", w/10d}, + {"wd12", w/12d}, + {"wd16", w/16d}, + {"wd32", w/32d}, + {"ssd2", ss/2d }, + {"ssd4", ss/4d }, + {"ssd6", ss/6d }, + {"ssd8", ss/8d }, + {"ssd16", ss/16d }, + {"ssd32", ss/32d }, + }; + } + + internal double CalculateFormula(string formula) + { + var tokens = formula.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var t = tokens[0]; + switch (t) + { + case "val": + var val = GetValue(tokens[1]); + return GetValue(tokens[1]); + case "*/": + var divBy = GetValue(tokens[3]); + if (divBy == 0) return 0; + var val1 = GetValue(tokens[1]); + var val2 = GetValue(tokens[2]); + + return (val1 * val2) / (double)divBy; + case "+-": + return (GetValue(tokens[1]) + GetValue(tokens[2])) - GetValue(tokens[3]); + case "+/": + divBy = GetValue(tokens[3]); + if (divBy == 0) return 0; + return (GetValue(tokens[1]) + GetValue(tokens[2])) / (double)divBy; + case "?:": + return GetValue(tokens[1]) > 0 ? GetValue(tokens[2]) : GetValue(tokens[3]); + case "sqrt": + return Math.Sqrt(Math.Abs(GetValue(tokens[1]))); + case "abs": + return Math.Abs(GetValue(tokens[1])); + case "min": + return Math.Min(GetValue(tokens[1]), GetValue(tokens[2])); + case "max": + return Math.Max(GetValue(tokens[1]), GetValue(tokens[2])); + case "mod": + return Math.Sqrt(Math.Pow((double)GetValue(tokens[1]), 2d) + Math.Pow((double)GetValue(tokens[2]), 2) + Math.Pow((double)GetValue(tokens[3]), 2)); + case "pin": + //if (y < x), then x = value of this guide else if (y > z), then z + double x = GetValue(tokens[1]); + double y = GetValue(tokens[2]); + double z = GetValue(tokens[3]); + + return (y < x ? x : y > z ? z : y); + case "sin": + var angleSin = GetValue(tokens[2]) / 60000D; + if (angleSin == 0d || angleSin == 180d) + { + return 0; + } + var radAngleSin = Math.Sin(MathHelper.Radians(angleSin)); + return (GetValue(tokens[1]) * radAngleSin); + case "cos": + var angleCos = GetValue(tokens[2]) / 60000D; + + if (angleCos == 90d || angleCos == 270d) + { + return 0; + } + var radAngleCos = Math.Cos(MathHelper.Radians(angleCos)); + return (GetValue(tokens[1]) * radAngleCos); + case "tan": + var angleTan = GetValue(tokens[2]) / 60000D; + + if (angleTan == 0d || angleTan == 90d) + { + //Tan technically undefined + return 0; + } + + return (GetValue(tokens[1]) * Math.Tan(MathHelper.Radians(angleTan))); + case "at2": + x = GetValue(tokens[1]); + y = GetValue(tokens[2]); + double angleRad = Math.Atan2(y, x); // radians + double angleDeg = angleRad * (180d / Math.PI); // degrees + + while (angleDeg < -360) + { + angleDeg += 360; // normalize to [0, 360) + } + while (angleDeg > 360) + { + angleDeg -= 360; + } + + return (angleDeg * 60000D); + case "cat2": + x = GetValue(tokens[1]); + y = GetValue(tokens[2]); + z = GetValue(tokens[3]); + + double angleRadCatOrig = Math.Atan2(z, y); // radians + double angleDegCat2Orig = angleRadCatOrig * (180.0 / Math.PI); // degrees + + if (angleDegCat2Orig == 90d || angleDegCat2Orig == 270d) + { + return 0; + } + + var dist = (x * Math.Cos(angleRadCatOrig)); + return dist; + case "sat2": + x = GetValue(tokens[1]); + y = GetValue(tokens[2]); + z = GetValue(tokens[3]); + + double angleRadSatOrig = Math.Atan2(z, y); // radians + double angleDegSat2Orig = angleRadSatOrig * (180.0 / Math.PI); // degrees + + if (angleDegSat2Orig == 0d || angleDegSat2Orig == 180d) + { + return 0; + } + + var sat2Rad = (x * Math.Sin(angleRadSatOrig)); + + return sat2Rad; + default: + if (_calculatedValues.TryGetValue(t, out var v)) + { + return v; + } + throw new InvalidOperationException($"Unknown function or variable {{{t}}}"); + } + + } + private double GetValue(string v) + { + if (double.TryParse(v, out var l)) + { + return l; + } + else + { + if (_calculatedValues.TryGetValue(v, out var cv)) + { + return cv; + } + throw new InvalidOperationException($"Unknown variable {{{v}}}"); + } + } + + public ShapeDefinition Clone() + { + return new ShapeDefinition(this); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeGuide.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeGuide.cs new file mode 100644 index 0000000000..8fb8940ac6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeGuide.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Diagnostics; + +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + /// + /// 20.1.9.11 Ecma part 1 + /// 20.1.10.76 - Preset Textbox Shape Types + /// + [DebuggerDisplay("{Name}-{Formula}={CalculatedValue}")] + public class ShapeGuide + { + public string Name { get; set; } + public string Formula { get; set; } + public double CalculatedValue + { + get; + set; + } + + public ShapeGuide Clone() + { + return new ShapeGuide() { Name=Name, Formula=Formula, CalculatedValue=CalculatedValue}; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapePositionCoordinate.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapePositionCoordinate.cs new file mode 100644 index 0000000000..a04cda38dd --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapePositionCoordinate.cs @@ -0,0 +1,20 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class ShapePositionCoordinate + { + public object X { get; set; } + public object Y { get; set; } + } +} diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/TextBoxRect.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/TextBoxRect.cs new file mode 100644 index 0000000000..b7dd100bba --- /dev/null +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/TextBoxRect.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer.ShapeDefinitions +{ + public class TextBoxRect + { + public string LeftName { get; set; } + public string RightName { get; set; } + public string TopName { get; set; } + public string BottomName { get; set; } + + public double LeftValue { get; set; } + public double RightValue { get; set; } + public double TopValue { get; set; } + public double BottomValue { get; set; } + + public TextBoxRect Clone() + { + return new TextBoxRect() + { + LeftName = LeftName, + RightName = RightName, + TopName = TopName, + BottomName = BottomName + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/Svg/IRender.cs b/src/EPPlus.DrawingRenderer/Svg/IRender.cs new file mode 100644 index 0000000000..84a3603bd9 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/IRender.cs @@ -0,0 +1,748 @@ +using DrawingRenderer.Constants; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.DrawingRenderer.Utils; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Utils; +using OfficeOpenXml.Utils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.DrawingRenderer +{ + public class SvgShapeRenderer : IShapeRenderer + { + public SvgShapeRenderer(BoundingBox bounds, StringBuilder outputStream, SvgRenderOptions options) + { + BasicShapesRenderer = new SvgBasicShapesRenderer(outputStream); + + //Override size. + if (options.Size.Width.HasValue) + { + bounds.Width = options.Size.WidthPixels; + } + if (options.Size.Height.HasValue) + { + bounds.Height = options.Size.HeightPixels; + } + + Bounds = bounds; + OutputStream = outputStream; + } + public IBasicIShapesRenderer BasicShapesRenderer { get; } + + public StringBuilder OutputStream { get; } + + public BoundingBox Bounds { get; } + public string ViewBox { get; set; } + public bool Render(List items) + { + OutputStream.Clear(); + OutputStream.Append($""); + PreRender(items); + foreach(var item in items) + { + switch(item.Type) + { + case RenderItemType.Group: + BasicShapesRenderer.GroupRenderer.Render((GroupRenderItem)item); + break; + case RenderItemType.Line: + BasicShapesRenderer.LineRenderer.Render((LineRenderItem)item); + break; + case RenderItemType.Rect: + BasicShapesRenderer.RectangleRenderer.Render((RectRenderItem)item); + break; + case RenderItemType.Ellipse: + BasicShapesRenderer.EllipseRenderer.Render((EllipseRenderItem)item); + break; + case RenderItemType.Path: + BasicShapesRenderer.PathRenderer.Render((PathRenderItem)item); + break; + case RenderItemType.Paragraph: + BasicShapesRenderer.ParagraphRenderer.Render((ParagraphRenderItem)item); + break; + case RenderItemType.UseReference: + BasicShapesRenderer.UseReferenceRenderer.Render((UseReferenceRenderItem)item); + break; + } + } + OutputStream.AppendLine(""); + return true; + } + + public bool PreRender(List items) + { + var defSb = new StringBuilder(); + var hs = new HashSet(); + var ix = 1; + + foreach (RenderItem item in items) + { + if(item is GroupRenderItem group) + { + foreach(var child in group.RenderItems) + { + WriteDefsForRenderItem(defSb, hs, ref ix, child); + } + } + else + { + WriteDefsForRenderItem(defSb, hs,ref ix, item); + } + } + + if (defSb.Length > 0) + { + OutputStream.Append(""); + OutputStream.Append(defSb); + OutputStream.Append(""); + } + + ////Remove all items that have already been rendered + //renderItems.RemoveAll(x => x is SvgRenderItem svgX && string.IsNullOrEmpty(svgX.DefId) == false); + return true; + } + Dictionary _defsCache = new Dictionary(); + private void WriteDefsForRenderItem(StringBuilder defSb, HashSet hs, ref int ix, RenderItem item) + { + string filter = ""; + if (item.GradientFill != null) + { + var key = item.GradientFill.GetKey(); + if (_defsCache.TryGetValue(key, out string? name) == false) + { + name = WriteGradient($"Gradient{ix}", defSb, hs, item.GradientFill, item.FillColorSource); + _defsCache[key] = name; + } + item.FillColor = $"Url(#{name})"; + } + else if (item.PatternFill != null) + { + var key = item.PatternFill.GetKey(); + if (_defsCache.TryGetValue(key, out string? name) == false) + { + name = WritePattern($"Pattern{item.PatternFill.PatternType}{ix}", defSb, hs, item.PatternFill, item.FillColorSource); + _defsCache[key] = name; + } + item.FillColor = $"Url(#{name})"; + } + else if (item.BlipFill != null) + { + var key = item.BlipFill.GetKey(); + + if (_defsCache.TryGetValue(key, out string? name) == false) + { + if (item.FillColorSource != PathFillMode.Norm) + { + item.FilterName = GetFilterName(ix); + } + + name = WriteBlip("Blip", defSb, hs, item, ref filter); + _defsCache[key] = name; + } + item.FillColor = $"Url(#{name})"; + } + if (item.BorderGradientFill != null) + { + var key = item.BorderGradientFill.GetKey(); + if (_defsCache.TryGetValue(key, out string? name) == false) + { + name = WriteGradient($"StrokeGradient{ix}", defSb, hs, item.BorderGradientFill, item.BorderColorSource); + _defsCache[key] = name; + } + item.BorderColor = $"Url(#{name})"; + } + if (item.GlowColor != null) + { + var key = item.GetFilterKey(); + if (_defsCache.TryGetValue(key, out string? name) == false) + { + if (string.IsNullOrEmpty(item.FilterName)) + { + name = GetFilterName(ix); + item.FilterName = $"Url(#{name})"; + filter = $""; + filter += $"" + + $"" + + $"" + + $""; + + _defsCache[key] = name; + } + } + else + { + item.FilterName = name; + } + } + if (item.OuterShadowEffect != null) + { + if (string.IsNullOrEmpty(item.FilterName)) + { + var key = item.GetFilterKey(); + if (_defsCache.TryGetValue(key, out string? name) == false) + { + var filterName = GetFilterName(ix); + item.FilterName = $"Url(#{filterName})"; + filter = $""; + _defsCache[key] = filterName; + } + else + { + item.FilterName = $"Url(#{name})"; + } + } + if (string.IsNullOrEmpty(filter) == false) + { + item.GetOuterShadowColor(out string shadowColor, out double opacity); + var dx = Math.Round(item.OuterShadowEffect.Distance * Math.Cos(MathHelper.Radians(item.OuterShadowEffect.Direction ?? 0D)), 2); + var dy = Math.Round(item.OuterShadowEffect.Distance * Math.Sin(MathHelper.Radians(item.OuterShadowEffect.Direction ?? 0D)), 2); + var blurRadius = item.OuterShadowEffect.BlurRadius ?? 0D / 2; + filter += $""; + } + } + if (string.IsNullOrEmpty(filter) == false) + { + defSb.Append(filter + ""); + } + ix++; + } + + private static string GetFilterName(int ix) + { + return $"item{ix}Filter"; + } + + private string WriteBlip(string namePrefix, StringBuilder defSb, HashSet hs, RenderItem item, ref string filter) + { + //, item.BlipFill, item.FillColorSource + var name = $"{namePrefix}"; + var fillMode = item.FillColorSource; + if (fillMode != PathFillMode.Norm) + { + if (hs.Contains(item.FilterName) == false) + { + switch (fillMode) + { + case PathFillMode.Lighten: + filter = $""; + break; + case PathFillMode.LightenLess: + filter = $""; + break; + case PathFillMode.DarkenLess: + filter = $""; + break; + case PathFillMode.Darken: + filter = $""; + break; + } + } + hs.Add(item.FilterName); + } + + if (hs.Contains(name)) return name; + hs.Add(name); + + defSb.Append($""); + defSb.Append($""); + defSb.Append($""); + return name; + } + private string WriteGradient(string namePrefix, StringBuilder defSb, HashSet hs, RenderGradientFill gradientFill, PathFillMode fillMode) + { + //var gs = gradientFill.Settings; + var name = $"{namePrefix}{fillMode}"; + var grUnits = gradientFill.UserSpaceOnUse ? " gradientUnits=\"userSpaceOnUse\"" : ""; + if (gradientFill.ShadePath == ShadePath.Linear && hs.Contains(name) == false) + { + hs.Add(name); + var xy = GetXy(gradientFill.LinearSettings?.Angle); + defSb.Append($""); + SetStopColors(defSb, gradientFill, fillMode); + defSb.Append(""); + } + else if (hs.Contains(name) == false) + { + hs.Add(name); + defSb.Append($""); + SetStopColors(defSb, gradientFill, fillMode); + defSb.Append($""); + } + + return name; + } + private string WritePattern(string namePrefix, StringBuilder defSb, HashSet hs, RenderPatternFill patternFill, PathFillMode fillMode) + { + var name = $"{namePrefix}{fillMode}"; + var afc = ColorUtils.GetAdjustedColor(fillMode, patternFill.ForegroundColor); + var abc = ColorUtils.GetAdjustedColor(fillMode, patternFill.BackgroundColor); + switch (patternFill.PatternType) + { + case FillPatternStyle.Pct5: + SetPatternHalf(defSb, name, afc, abc, 10, 10); + break; + case FillPatternStyle.Pct10: + SetPatternHalf(defSb, name, afc, abc, 10, 5); + break; + case FillPatternStyle.Pct20: + SetPatternHalf(defSb, name, afc, abc, 4, 4); + break; + case FillPatternStyle.Pct25: + SetPatternHalf(defSb, name, afc, abc, 4, 2); + break; + case FillPatternStyle.Pct30: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Pct30); + break; + case FillPatternStyle.Pct40: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Pct40); + break; + case FillPatternStyle.Pct50: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Pct50); + break; + case FillPatternStyle.Pct60: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Pct60); + break; + case FillPatternStyle.Pct70: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Pct70); + break; + case FillPatternStyle.Pct75: + SetPatternHalf(defSb, name, abc, afc, 4, 2); + break; + case FillPatternStyle.Pct80: + SetPatternHalf(defSb, name, abc, afc, 4, 4); + break; + case FillPatternStyle.Pct90: + SetPatternHalf(defSb, name, abc, afc, 10, 5); + break; + case FillPatternStyle.LtHorz: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LtHorz); + break; + case FillPatternStyle.LtVert: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LtVert); + break; + case FillPatternStyle.LtUpDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LtUpDiag); + break; + case FillPatternStyle.LtDnDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LtDnDiag); + break; + case FillPatternStyle.DkVert: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DkVert); + break; + case FillPatternStyle.DkHorz: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DkHorz); + break; + case FillPatternStyle.DkUpDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DkUpDiag); + break; + case FillPatternStyle.DkDnDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DkDnDiag); + break; + case FillPatternStyle.WdUpDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.WdUpDiag); + break; + case FillPatternStyle.WdDnDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.WdDnDiag); + break; + case FillPatternStyle.NarVert: + SetPatternArray(defSb, name, afc, abc, PatternArrays.NarVert); + break; + case FillPatternStyle.NarHorz: + SetPatternArray(defSb, name, afc, abc, PatternArrays.NarHorz); + break; + case FillPatternStyle.Vert: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Vert); + break; + case FillPatternStyle.Horz: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Horz); + break; + case FillPatternStyle.DashDnDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DashDnDiag); + break; + case FillPatternStyle.DashUpDiag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DashUpDiag); + break; + case FillPatternStyle.DashHorz: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DashHorz); + break; + case FillPatternStyle.DashVert: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DashVert); + break; + case FillPatternStyle.SmConfetti: + SetPatternArray(defSb, name, afc, abc, PatternArrays.SmConfetti); + break; + case FillPatternStyle.LgConfetti: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LgConfetti); + break; + case FillPatternStyle.ZigZag: + SetPatternArray(defSb, name, afc, abc, PatternArrays.ZigZag); + break; + case FillPatternStyle.Wave: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Wave); + break; + case FillPatternStyle.DiagBrick: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DiagBrick); + break; + case FillPatternStyle.HorzBrick: + SetPatternArray(defSb, name, afc, abc, PatternArrays.HorzBrick); + break; + case FillPatternStyle.Weave: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Weave); + break; + case FillPatternStyle.Plaid: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Plaid); + break; + case FillPatternStyle.Divot: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Divot); + break; + case FillPatternStyle.DotGrid: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DotGrid); + break; + case FillPatternStyle.DotDmnd: + SetPatternArray(defSb, name, afc, abc, PatternArrays.DotDmnd); + break; + case FillPatternStyle.Shingle: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Shingle); + break; + case FillPatternStyle.Trellis: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Trellis); + break; + case FillPatternStyle.Sphere: + SetPatternArray(defSb, name, afc, abc, PatternArrays.Sphere); + break; + case FillPatternStyle.SmGrid: + SetPatternArray(defSb, name, afc, abc, PatternArrays.SmGrid); + break; + case FillPatternStyle.LgGrid: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LgGrid); + break; + case FillPatternStyle.SmCheck: + SetPatternArray(defSb, name, afc, abc, PatternArrays.SmCheck); + break; + case FillPatternStyle.LgCheck: + SetPatternArray(defSb, name, afc, abc, PatternArrays.LgCheck); + break; + case FillPatternStyle.OpenDmnd: + SetPatternArray(defSb, name, afc, abc, PatternArrays.OpenDmnd); + break; + case FillPatternStyle.SolidDmnd: + SetPatternArray(defSb, name, afc, abc, PatternArrays.SolidDmnd); + break; + default: + break; + } + return name; + } + /// + /// Sets the pattern to the size with one point top-left and on point middle (x/y). + /// + /// + /// + /// + /// + /// + /// + private static void SetPatternHalf(StringBuilder defSb, string name, Color afc, Color abc, int width, int height) + { + defSb.Append($""); + + + defSb.Append($""); + defSb.Append($""); + defSb.Append($""); + defSb.Append($""); + } + + private static object WriteFillColor(Color c) + { + double opacity = -1; + if (c.A < 255 && c != Color.Empty) + { + opacity = c.A / 255D * 100; + } + if (opacity == -1) + { + return $"fill=\"#{c.To6CharHexString()}\""; + } + else + { + return $"fill=\"#{c.To6CharHexString()}\" fill-opacity=\"{opacity}%\""; + } + } + + private static void SetPatternArray(StringBuilder defSb, string name, Color afc, Color abc, short[][] pathArray) + { + var height = pathArray.GetLength(0); + var width = pathArray[0].GetLength(0); + defSb.Append($""); + defSb.Append($""); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if (pathArray[y][x] == 1) + { + defSb.Append($""); + } + } + } + defSb.Append($""); + } + + private string GetScaling(RenderGradientFill gradientFill) + { + var sb = new StringBuilder(); + var t = gradientFill.FocusPoint.TopOffset / 100; + var b = gradientFill.FocusPoint.BottomOffset / 100; + var l = gradientFill.FocusPoint.LeftOffset / 100; + var r = gradientFill.FocusPoint.RightOffset / 100; + + var tt = gradientFill.TileRectangle.TopOffset / 100; + var tb = gradientFill.TileRectangle.BottomOffset / 100; + var tl = gradientFill.TileRectangle.LeftOffset / 100; + var tr = gradientFill.TileRectangle.RightOffset / 100; + + var dy = Math.Abs(t - b); + var dx = Math.Abs(l - r); + //var scaleTo = Math.Min(dy, dx); + //var mult = 0.5 + (scaleTo / 2); + var cx = Bounds.Width * l; + var cy = Bounds.Height * t; + //var radX = Math.Abs((t - b )) * _svgDrawing.FontSize.Item1; + //var radY = Math.Abs((l - r)) * _svgDrawing.FontSize.Item2; + var rx = Bounds.Width * 0.5 * (Math.Abs(t - tb) + Math.Abs(b - tt)); + var ry = Bounds.Height * 0.5 * (Math.Abs(l - tr) + Math.Abs(r - tl)); + + var rad = Math.Sqrt(rx * rx + ry * ry); + + sb.Append($"cx=\"{cx.ToString(CultureInfo.InvariantCulture)}\" cy=\"{cy.ToString(CultureInfo.InvariantCulture)}\" "); + + //if(tt-tb != 0) + //{ + // sb.Append($"fy=\"{fy.ToString(CultureInfo.InvariantCulture)}\" "); + //} + if (dy > 0 && dy < 1) + { + var fy = cy * (1 + dy); + sb.Append($"fy=\"{fy.ToString(CultureInfo.InvariantCulture)}\" "); + } + + if (dx > 0 && dx < 1) + { + var fx = cx * (1 + dx); + sb.Append($"fx=\"{fx.ToString(CultureInfo.InvariantCulture)}\" "); + } + sb.Append($"r=\"{rad.ToString(CultureInfo.InvariantCulture)}\" "); + sb.Append($"gradientUnits=\"userSpaceOnUse\" spreadMethod=\"pad\" gradientTransform=\"matrix(1 0 0 1 1 1)\" "); + + return sb.ToString(); + } + + private void SetStopColors(StringBuilder defSb, RenderGradientFill gradientFill, PathFillMode fillMode) + { + //Svg requires starting at 0 and moving towards 100% Excel sometimes starts at 100 + //Sort to get around that + var sortedGradientColors = gradientFill.Colors.OrderBy(x => x.Position); + + foreach (var c in sortedGradientColors) + { + var color = ColorUtils.GetAdjustedColor(fillMode, c.Color); + // TODO: check if ix should be increased...? + var op = c.Opacity; + defSb.Append($""); + } + } + + private string GetXy(double? angle) + { + if (angle.HasValue && angle != 0) + { + var x1 = 0D; + var x2 = 0D; + var y1 = 0D; + var y2 = 0D; + angle %= 360; + if (angle <= 90) + { + x2 = 1D - Math.Sin(MathHelper.Radians(angle.Value)); + y2 = Math.Sin(MathHelper.Radians(angle.Value)); + } + else if (angle <= 180) + { + y2 = Math.Sin(MathHelper.Radians(angle.Value)); + x1 = 1D - Math.Sin(MathHelper.Radians(angle.Value)); + } + else if (angle <= 270) + { + y1 = Math.Sin(MathHelper.Radians(angle.Value - 180)); + x1 = 1D - Math.Sin(MathHelper.Radians(angle.Value - 180)); + } + else + { + y1 = Math.Sin(MathHelper.Radians(angle.Value - 180)); + x2 = 1D - Math.Sin(MathHelper.Radians(angle.Value - 180)); + } + + return $" x1=\"{(x1).ToString("0.00%", CultureInfo.InvariantCulture)}\" x2=\"{(x2).ToString("0.00%", CultureInfo.InvariantCulture)}\" y1=\"{y1.ToString("0.00%", CultureInfo.InvariantCulture)}\" y2=\"{y2.ToString("0.00%", CultureInfo.InvariantCulture)}\""; + } + return ""; + } + + private string GetOpacity(double opacity) + { + if (opacity > 0 && opacity < 1) + { + return $"stop-opacity=\"{opacity.ToString("0")}%\""; + } + return ""; + } + + private string SetStretchTileProps(RenderBlipFill blipFill) + { + if (blipFill.Stretch) + { + var x = Bounds.Width * blipFill.StretchOffset.LeftOffset / 100; + var y = Bounds.Height * blipFill.StretchOffset.TopOffset / 100; + var width = Bounds.Width - x - Bounds.Width * blipFill.StretchOffset.RightOffset / 100; + var height = Bounds.Height - x - Bounds.Height * blipFill.StretchOffset.BottomOffset / 100; + return $" preserveAspectRatio=\"none\" x=\"{x.ToString(CultureInfo.InvariantCulture)}\" y=\"{y.ToString(CultureInfo.InvariantCulture)}\" width=\"{width.PointToPixelString()}\" height=\"{height.PointToPixelString()}\" "; + } + else if (!(blipFill.Tile.HorizontalOffset == 0 && blipFill.Tile.VerticalOffset == 0 && + blipFill.Tile.HorizontalRatio == 100 && blipFill.Tile.VerticalRatio == 100 && blipFill.Tile.FlipMode == TileFlipMode.None)) + { + var flip = ""; + switch (blipFill.Tile.FlipMode) + { + case TileFlipMode.X: + flip = $" transform=\"translate({Bounds.Width.ToString(CultureInfo.InvariantCulture)}, 0) scale(-1, 1)\""; + break; + case TileFlipMode.Y: + flip = $" transform=\"translate(0, {Bounds.Height.ToString(CultureInfo.InvariantCulture)}) scale(1, -1)\""; + break; + case TileFlipMode.XY: + flip = $" transform=\"translate({Bounds.Width.ToString(CultureInfo.InvariantCulture)}, {Bounds.Height.ToString(CultureInfo.InvariantCulture)}) scale(-1, -1)\""; + break; + } + return $"{flip}"; + } + + return ""; + } + + private object GetImageAsHref(RenderBlipFill blipFill) + { + return $"data:{blipFill.ContentType};base64," + Convert.ToBase64String(blipFill.ImageBytes); + } + } + + public interface IShapeRenderer + { + IBasicIShapesRenderer BasicShapesRenderer { get; } + T OutputStream { get; } + bool PreRender(List items); + BoundingBox Bounds { get; } + string ViewBox { get; set; } + bool Render(List items); + } + + public class SvgBasicShapesRenderer : IBasicIShapesRenderer + { + public SvgBasicShapesRenderer(StringBuilder outputStream) + { + LineRenderer = new SvgLineRenderer(outputStream); + RectangleRenderer = new SvgRectRenderer(outputStream); + EllipseRenderer = new SvgEllipseRenderer(outputStream); + PathRenderer = new SvgPathRenderer(outputStream); + ParagraphRenderer = new SvgParagraphRenderer(this, outputStream); + GroupRenderer = new SvgGroupRenderer(this, outputStream); + TextRunRenderer = new SvgTextRunRenderer(outputStream); + TitleRenderer = new SvgTitleRenderer(outputStream); + UseReferenceRenderer = new SvgUseReferenceRenderer(outputStream); + + // ImageRenderer = new SvgImageRenderer(outputStream); + } + public BaseRenderer GroupRenderer { get; } + public BaseRenderer RectangleRenderer { get; } + public BaseRenderer EllipseRenderer { get; } + public BaseRenderer PathRenderer { get; } + //public BaseRenderer ImageRenderer { get; } + public BaseRenderer LineRenderer { get; } + public BaseRenderer TitleRenderer { get; } + public BaseRenderer ParagraphRenderer { get; } + public BaseRenderer TextRunRenderer { get; } + public BaseRenderer UseReferenceRenderer { get; } + + public void Render(RenderItem item) + { + switch(item.Type) + { + case RenderItemType.Group: + GroupRenderer.Render((GroupRenderItem)item); + break; + case RenderItemType.Line: + LineRenderer.Render((LineRenderItem)item); + break; + case RenderItemType.Rect: + RectangleRenderer.Render((RectRenderItem)item); + break; + case RenderItemType.Ellipse: + EllipseRenderer.Render((EllipseRenderItem)item); + break; + case RenderItemType.Path: + PathRenderer.Render((PathRenderItem)item); + break; + case RenderItemType.Text: + throw new NotImplementedException(); + break; + case RenderItemType.CommentTitle: + TitleRenderer.Render((TitleRenderItem)item); + break; + case RenderItemType.Paragraph: + ParagraphRenderer.Render((ParagraphRenderItem)item); + break; + case RenderItemType.UseReference: + UseReferenceRenderer.Render((UseReferenceRenderItem)item); + break; + case RenderItemType.TextRun: + TextRunRenderer.Render((TextRunRenderItem)item); + break; + } + } + } + public interface IBasicIShapesRenderer + { + public BaseRenderer GroupRenderer { get; } + public BaseRenderer RectangleRenderer { get; } + public BaseRenderer EllipseRenderer { get; } + public BaseRenderer PathRenderer { get; } + //public BaseRenderer ImageRenderer { get; } + public BaseRenderer LineRenderer { get; } + public BaseRenderer TitleRenderer { get; } + public BaseRenderer ParagraphRenderer { get; } + public BaseRenderer UseReferenceRenderer { get; } + + public void Render(RenderItem item); + } + public abstract class BaseRenderer + { + protected BaseRenderer(T outputStream) + { + OutputStream = outputStream; + } + public T OutputStream { get; } + public abstract void Render(T2 item); + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/Options/SvgRenderOptions.cs b/src/EPPlus.DrawingRenderer/Svg/Options/SvgRenderOptions.cs new file mode 100644 index 0000000000..ea42b7c955 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/Options/SvgRenderOptions.cs @@ -0,0 +1,23 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer.Svg +{ + /// + /// Options for rendering drawings to svg. + /// + public class SvgRenderOptions + { + public SvgSize Size { get; } = new SvgSize(); + } + +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/Svg/Options/SvgSize.cs b/src/EPPlus.DrawingRenderer/Svg/Options/SvgSize.cs new file mode 100644 index 0000000000..ba651d948c --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/Options/SvgSize.cs @@ -0,0 +1,70 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Utils; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgSize + { + /// + /// Overrides the width for ouput the svg image. + /// + public double? Width { get; set; } = null; + /// + /// Overrides the height of the ouput svg drawing. + /// + public double? Height { get; set; } = null; + public SvgSizeUnit Unit { get; set; } = SvgSizeUnit.Pixels; + public double WidthPixels + { + get + { + return GetPixels(Width ?? 0D, Unit); + } + } + public double HeightPixels + { + get + { + return GetPixels(Height ?? 0D, Unit); + } + } + + internal static double GetPixels(double width, SvgSizeUnit unit) + { + switch(unit) + { + case SvgSizeUnit.Points: + return width.PointToPixel(); + case SvgSizeUnit.Inches: + return width * 96; + case SvgSizeUnit.Centimeters: + return width * 96 / 2.54; + case SvgSizeUnit.Millimeters: + return width * 96 / 25.4; + default: //Pixels + return width; + } + } + } +} + + public enum SvgSizeUnit + { + Pixels=0, + Points=1, + Millimeters, // mm + Centimeters, // cm + Inches // in +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgBaseRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgBaseRenderer.cs new file mode 100644 index 0000000000..3bf5da9712 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgBaseRenderer.cs @@ -0,0 +1,120 @@ +using EPPlus.DrawingRenderer.RenderItems; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public abstract class SvgBaseRenderer : BaseRenderer where T : RenderItem + { + protected SvgBaseRenderer(StringBuilder outputStream) : base(outputStream) + { + + } + + /// + /// Used if you wish to render base to a different string builder first + /// + /// + /// + protected void RenderBaseToSpecified(T item, StringBuilder sb) + { + if (item.Bounds.Name != null) + { + sb.Append($" id=\"{item.Bounds.Name}\" "); + } + + if (string.IsNullOrEmpty(item.DefId) == false) + { + sb.Append($"id=\"{item.DefId}\" "); + } + + if (string.IsNullOrEmpty(item.FillColor) == false) + { + sb.Append($"fill=\"{item.FillColor}\" "); + } + //If fill is null it may in e.g. Rect still get the color black which can have an opacity + if (item.FillOpacity != null && item.FillOpacity != 1) + { + sb.Append($"opacity=\"{item.FillOpacity.Value.ToString(CultureInfo.InvariantCulture)}\" "); + } + if (string.IsNullOrEmpty(item.FilterName) == false) + { + sb.Append($"filter=\"{item.FilterName}\" "); + } + + if (item.BorderWidth.HasValue) + { + if (string.IsNullOrEmpty(item.BorderColor) == false) + { + sb.Append($"stroke=\"{item.BorderColor}\" "); + } + var v = item.BorderWidth.Value * Constants.EMU_PER_POINT / Constants.EMU_PER_PIXEL; + sb.Append($"stroke-width=\"{v.ToString(CultureInfo.InvariantCulture)}\" "); + + if (item.BorderDashArray != null) + { + var BorderDashArrayStr = item.BorderDashArray.Select(x => + x.ToString(CultureInfo.InvariantCulture)).ToArray(); + + sb.Append($"stroke-dasharray=\"" + $"{string.Join(",", BorderDashArrayStr)}\" "); + } + if (item.BorderOpacity.HasValue) + { + sb.Append($" stroke-opacity=\"{(Math.Round(item.BorderOpacity.Value * 100)).ToString(CultureInfo.InvariantCulture)}%\" "); + } + } + + if (item.TransformOrigin != null) + { + sb.Append($" transform-origin=\"{item.TransformOrigin.X.ToString(CultureInfo.InvariantCulture)} {item.TransformOrigin.Y.ToString(CultureInfo.InvariantCulture)}\" "); + } + + if (item.StrokeMiterLimit.HasValue) + { + sb.Append($"stroke-miterlimit =\"{item.StrokeMiterLimit}\" "); + } + } + + protected void RenderBase(T item) + { + var sb = OutputStream; + RenderBaseToSpecified(item, sb); + } + protected void RenderCompoundItems(T li, double? borderWidth, string color, string filter) + { + var tmpBorderWidth = li.BorderWidth; + string tmpBorderColor = null; + li.BorderWidth = borderWidth ?? li.BorderWidth; + if (string.IsNullOrEmpty(color) == false) + { + tmpBorderColor = li.BorderColor; + li.BorderColor = color; + } + + RenderBase(li); + var sb = OutputStream; + if (li.LineCap != LineCap.Flat) + { + sb.AppendFormat(" stroke-linecap=\"{0}\"", li.LineCap == LineCap.Round ? "round" : "square"); + } + if (li.LineJoin != LineJoin.Miter) + { + sb.AppendFormat(" stroke-linejoin=\"{0}\"", li.LineJoin); + } + + if (string.IsNullOrEmpty(filter) == false) + { + sb.Append(" " + filter); + } + + sb.AppendFormat("/>"); + + li.BorderWidth = tmpBorderWidth; + if (string.IsNullOrEmpty(color) == false) + { + li.BorderColor = tmpBorderColor; + } + } + + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgEllipseRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgEllipseRenderer.cs new file mode 100644 index 0000000000..ca9697120b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgEllipseRenderer.cs @@ -0,0 +1,26 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgEllipseRenderer : SvgBaseRenderer + { + public SvgEllipseRenderer(StringBuilder outputStream) : base(outputStream) + { + } + public override void Render(EllipseRenderItem item) + { + OutputStream.AppendFormat(""); + } + + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgGroupRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgGroupRenderer.cs new file mode 100644 index 0000000000..8f416409d6 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgGroupRenderer.cs @@ -0,0 +1,99 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgGroupRenderer : SvgBaseRenderer + { + const string transformRotate = "rotate({0})"; + const string transformScale = "scale({0}, {1})"; + + IBasicIShapesRenderer _shapeRenderer; + public SvgGroupRenderer(IBasicIShapesRenderer shapeRenderer, StringBuilder outputStream) : base(outputStream) + { + _shapeRenderer = shapeRenderer; + } + internal string Suffix = "px"; + public override void Render(GroupRenderItem item) + { + string combinedTransform = GetCombinedTransformString(item); + + //Neccesary as fallback for e.g. DataLabels + string fillPropery = ""; + + //We may need special handling for fill-color 'none' as it is sometimes transparent and sometimes un-applied. + if (string.IsNullOrEmpty(item.FillColor) == false) + { + fillPropery = $" fill=\"{item.FillColor}\" "; + } + + OutputStream.Append($""); + + foreach (var childItem in item.RenderItems) + { + _shapeRenderer.Render(childItem); + } + + OutputStream.Append(""); + } + string GetCombinedTransformString(GroupRenderItem item) + { + string positionStr = ""; + string rotationStr = GetRotationStr(item); + string scalingStr = GetScalingStr(item); + + + //if (item.TranslationOffset != null && (item.TranslationOffset.Left == 0 && item.TranslationOffset.Top == 0) == false) + //{ + // positionStr = string.Format(transformTranslate, item.TranslationOffset.Left.PointToPixelString(), item.TranslationOffset.Top.PointToPixelString()) + " "; + //} + + positionStr = string.Format("translate({0}, {1})", item.Bounds.Left.PointToPixelString(), item.Bounds.Top.PointToPixelString()) + " "; + + return positionStr + rotationStr + scalingStr; + } + string GetTransformOrigin(GroupRenderItem item) + { + string tOrigin = string.Empty; + + if (item.TransformOrigin != null && (item.TransformOrigin.X == 0 && item.TransformOrigin.Y == 0) == false) + { + tOrigin = $"transform-origin=\"{item.TransformOrigin.X.PointToPixelString()} {item.TransformOrigin.Y.PointToPixelString()}\""; + } + return tOrigin; + } + + + string GetScalingStr(GroupRenderItem item) + { + var scaleStr = string.Empty; + + if (item.Scale != null) + { + scaleStr = string.Format(transformScale, item.Scale.X.ToString(CultureInfo.InvariantCulture), item.Scale.Y.ToString(CultureInfo.InvariantCulture)) + " "; + } + + return scaleStr; + } + + string GetRotationStr(GroupRenderItem item) + { + if (double.IsNaN(item.Rotation) == false && item.Rotation!=0) + { + string rot = item.Rotation.ToString(CultureInfo.InvariantCulture); + + if (item.RotationPoint != null && item.RotationPoint != item.TranslationOffset) + { + rot += $", {item.RotationPoint.Left.PointToPixelString()}, {item.RotationPoint.Top.PointToPixelString()}" + " "; + } + + return string.Format(transformRotate, rot); + } + + return string.Empty; + } + + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgLineRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgLineRenderer.cs new file mode 100644 index 0000000000..edca4f7704 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgLineRenderer.cs @@ -0,0 +1,92 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgLineRenderer : SvgBaseRenderer + { + public SvgLineRenderer(StringBuilder outputStream) : base(outputStream) + { + } + public override void Render(LineRenderItem item) + { + var li = (LineRenderItem)item; + StringBuilder sb = OutputStream; + //Draw transparent lines to create the compond line effect, as SVG does not support compound lines natively + switch (li.CompoundLineStyle) + { + case CompoundLineStyle.Double: + li.LineCap = LineCap.Flat; + var name = $"double-stroke-{Guid.NewGuid().ToString()}"; + sb.Append($""); + + RenderLineItem(li, li.BorderWidth, "white", null); + RenderLineItem(li, li.BorderWidth * (3D / 7D), "black", null); + sb.Append($""); + break; + case CompoundLineStyle.DoubleThickThin: + WriteThickThin(li, "double-thick-thin-stroke-{0}", (li.BorderWidth ?? 1D) * 1D / 7D); + break; + case CompoundLineStyle.DoubleThinThick: + WriteThickThin(li, "double-thin-thick-stroke-{0}", ((li.BorderWidth ?? 1D) * 1D / 7D) * -1); + break; + case CompoundLineStyle.TripleThinThickThin: + var guid = Guid.NewGuid().ToString(); + var gapOffset = 5 * li.BorderWidth.Value / 16; + name = $"triple-stroke-{guid}"; + sb.Append($""); + sb.Append($""); + sb.Append($""); + sb.Append($""); + RenderLineItem(li, li.BorderWidth, "white", null); + RenderLineItem(li, li.BorderWidth * (1D / 8D), "black", $"filter=\"url(#gap-left-{guid})\""); + RenderLineItem(li, li.BorderWidth * (1D / 8D), "black", $"filter=\"url(#gap-right-{guid})\""); + sb.Append($""); + break; + default: + RenderLineItem(li, null, null, null); + break; + } + } + private void WriteThickThin(LineRenderItem li, string name, double gapOffset) + { + var sb = OutputStream; + var guid = Guid.NewGuid().ToString(); + name = string.Format(name, guid); + string gapFilterName = $"f-gap-shift-{guid}"; + sb.Append(""); + sb.Append($""); + sb.Append($""); + RenderLineItem(li, li.BorderWidth, "white", null); + RenderLineItem(li, li.BorderWidth * (1D / 4D), "black", $"filter=\"url(#{gapFilterName})\""); + sb.Append($""); + } + internal string Suffix = "px"; + + private void RenderLineItem(LineRenderItem li, double? borderWidth, string color, string filter) + { + var sb = OutputStream; + if (Suffix == "%") + { + + sb.AppendFormat(" + { + IBasicIShapesRenderer _shapeRenderer; + public SvgParagraphRenderer(IBasicIShapesRenderer shapeRenderer, StringBuilder outputStream) : base(outputStream) + { + _shapeRenderer = shapeRenderer; + } + internal string Suffix = "px"; + public override void Render(ParagraphRenderItem item) + { + var sb = OutputStream; + var fontSize = item.DefaultParagraphFont.Size.PointToPixel().ToString(CultureInfo.InvariantCulture); + + sb.AppendLine($""); + + sb.AppendLine("paragraph "); + + //if (DisplayBounds) + //{ + // sb.AppendLine($""); + // sb.AppendLine("Bounding-Box: Paragraph "); + // SvgRenderRectItem visualBoundingBox = new SvgRenderRectItem(DrawingRenderer, ParentTextBody.Bounds); + + // //Left/Top handled by transform + // visualBoundingBox.Bounds.Width = item.Bounds.Width; + // visualBoundingBox.Bounds.Height = itemBounds.Height; + + // visualBoundingBox.FillOpacity = 0.3; + // visualBoundingBox.FillColor = "red"; + // visualBoundingBox.Render(sb); + // sb.AppendLine($""); + + //} + + //var bb = new SvgRenderRectItem(DrawingRenderer, Bounds); + ////The bb is affected by the Transform so set pos to zero + //if (IsFirstParagraph == false) + //{ + // bb.Y = 0; + //} + //bb.X = 0; + + //bb.Width = Bounds.Width; + //bb.Height = Bounds.Height; + //bb.FillColor = FillColor; + //bb.FillOpacity = 0.3; + //bb.Render(sb); + + //Render text run debug boxes as we cannot place the rects after or inside the text element + + //if (Runs.Count > 0) + //{ + // //double lastWidth = 0; + + // var bbLines = new SvgRenderRectItem(); + + // foreach (var textRun in Runs) + // { + // ////render txtRun debug + // bbLines.X = textRun.Bounds.Left; + // bbLines.Width = textRun.Bounds.Width; + // if (IsFirstParagraph == false) + // { + // bbLines.Y = -textRun.FontSizeInPixels.PixelToPoint(); + // } + + // //Render each line debug + // bbLines.FillColor = "purple"; + // for (int i = 0; i < textRun.Lines.Count; i++) + // { + // if (i > 0) + // { + // bbLines.Y += textRun.YIncreasePerLine[i]; + // //lastWidth = 0; + // bbLines.X = 0; + // } + // else + // { + // bbLines.X = textRun.Bounds.Left; + // } + + // bbLines.Height = textRun.FontSizeInPixels; + // bbLines.Width = textRun.PerLineWidth[i]; + // bbLines.RenderRect(sb); + // } + // } + //} + + sb.Append(""); + + if (item.Runs != null && item.Runs.Count > 0) + { + foreach (var textRun in item.Runs) + { + _shapeRenderer.Render(textRun); + } + } + + sb.AppendLine(""); + sb.AppendLine(""); + } + + //string GetFontStyleAttributes() + //{ + // string fontStyleAttributes = " "; + + // if (_isItalic) + // { + // fontStyleAttributes += "font-style=\"italic\" "; + // } + // if (_isBold) + // { + // fontStyleAttributes += "font-weight=\"bold\" "; + // } + // if (_underLineType != eUnderLineType.None | _strikeType != eStrikeType.No) + // { + + // fontStyleAttributes += "text-decoration=\" "; + // if (_underLineType != eUnderLineType.None) + // { + // switch (_underLineType) + // { + // case eUnderLineType.Single: + // fontStyleAttributes += "underline"; + // break; + // //These are all css only apparently + // //case eUnderLineType.Double: + // // fontStyleAttributes += "double"; + // // break; + // //case eUnderLineType.Dotted: + // // fontStyleAttributes += "dotted"; + // // break; + // //case eUnderLineType.Dash: + // // fontStyleAttributes += "dashed"; + // // break; + // //case eUnderLineType.Wavy: + // // fontStyleAttributes += "wavy"; + // // break; + // default: + // fontStyleAttributes += "underline"; + // break; + // //throw new NotImplementedException("Not implemented yet"); + // } + // } + + // if (_strikeType == eStrikeType.Single) + // { + // //Has to check if Both underline and strike + // if (_underLineType != eUnderLineType.None) + // { + // fontStyleAttributes += ","; + // } + // fontStyleAttributes += "line-through"; + // } + + // fontStyleAttributes += "\" "; + // } + + // return fontStyleAttributes; + //} + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgPathRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgPathRenderer.cs new file mode 100644 index 0000000000..9fe9acde34 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgPathRenderer.cs @@ -0,0 +1,99 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgPathRenderer : SvgBaseRenderer + { + public SvgPathRenderer(StringBuilder outputStream) : base(outputStream) + { + } + public override void Render(PathRenderItem path) + { + StringBuilder sb = OutputStream; + //Draw transparent lines to create the compond line effect, as SVG does not support compound lines natively + switch (path.CompoundLineStyle) + { + case CompoundLineStyle.Single: + RenderPathItem(path, null, null, null); + break; + case CompoundLineStyle.Double: + var name = $"double-stroke-{Guid.NewGuid().ToString()}"; + sb.Append($""); + + RenderPathItem(path, path.BorderWidth, "white", null); + RenderPathItem(path, path.BorderWidth * (3D / 7D), "black", null); + sb.Append($""); + break; + case CompoundLineStyle.DoubleThickThin: + WriteThickThin(path, (path.BorderWidth ?? 1D) * 1D / 7D); + break; + case CompoundLineStyle.DoubleThinThick: + WriteThickThin(path, ((path.BorderWidth ?? 1D) * 1D / 7D) * -1); + break; + case CompoundLineStyle.TripleThinThickThin: + var guid = Guid.NewGuid().ToString(); + var gapOffset = 5 * (path.BorderWidth??1D) / 16; + name = $"triple-stroke-{guid}"; + sb.Append($""); + sb.Append($""); + sb.Append($""); + sb.Append($""); + RenderPathItem(path, path.BorderWidth, "white", null); + RenderPathItem(path, path.BorderWidth * (1D / 8D), "black", $"filter=\"url(#gap-left-{guid})\""); + RenderPathItem(path, path.BorderWidth * (1D / 8D), "black", $"filter=\"url(#gap-right-{guid})\""); + sb.Append($""); + break; + } + } + private void RenderPathItem(PathRenderItem path, double? borderWidth, string color, string filter) + { + OutputStream.Append($" 0) + { + OutputStream.Remove(OutputStream.Length - 1, 1); + } + } + + private void WriteThickThin(PathRenderItem path, double gapOffset) + { + var guid = Guid.NewGuid().ToString(); + var name = $"double-thick-thin-stroke-{guid}"; + string gapFilterName = $"f-gap-shift-{guid}"; + OutputStream.Append(""); + OutputStream.Append($""); + OutputStream.Append($""); + RenderPathItem(path, path.BorderWidth, "white", null); + RenderPathItem(path, path.BorderWidth * (1 / 4D), "black", $"filter=\"url(#{gapFilterName})\""); + OutputStream.Append($""); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgRectRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgRectRenderer.cs new file mode 100644 index 0000000000..9ca3b3ff3c --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgRectRenderer.cs @@ -0,0 +1,49 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgRectRenderer : SvgBaseRenderer + { + public SvgRectRenderer(StringBuilder outputStream) : base(outputStream) + { + + } + internal string Suffix = "px"; + public override void Render(RectRenderItem item) + { + if (Suffix == "%") + { + OutputStream.AppendFormat(""); + } + } + public class SvgUseReferenceRenderer : SvgBaseRenderer + { + public SvgUseReferenceRenderer(StringBuilder outputStream) : base(outputStream) + { + } + internal string Suffix = "px"; + public override void Render(UseReferenceRenderItem item) + { + string renderStr = $""; + OutputStream.Append(renderStr); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgTextRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgTextRenderer.cs new file mode 100644 index 0000000000..2d85760517 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgTextRenderer.cs @@ -0,0 +1,40 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgTextRenderer : SvgBaseRenderer + { + public SvgTextRenderer(StringBuilder outputStream) : base(outputStream) + { + + } + internal string Suffix = "px"; + public override void Render(ParagraphRenderItem item) + { + foreach(var c in item.Runs) + { + + } + //if (Suffix == "%") + //{ + // OutputStream.AppendFormat(""); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgTextRunRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgTextRunRenderer.cs new file mode 100644 index 0000000000..d1c9783ae8 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgTextRunRenderer.cs @@ -0,0 +1,189 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.SvgItem; +using EPPlus.Export.ImageRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Utils; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + internal class SvgTextRunRenderer : SvgBaseRenderer + { + string UnderlineColorString = string.Empty; + + public SvgTextRunRenderer(StringBuilder outputStream) : base(outputStream) + { + + } + + string GetFontStyleAttributes(TextRunRenderItem textRun) + { + string fontStyleAttributes = " "; + + if (textRun._isItalic) + { + fontStyleAttributes += "font-style=\"italic\" "; + } + if (textRun._isBold) + { + fontStyleAttributes += "font-weight=\"bold\" "; + } + + string content = ""; + + if (textRun._underLineType != eDrawingUnderLineType.None | textRun._strikeType != eDrawingStrikeType.No) + { + string underlineContent = ""; + if (textRun._underLineType != eDrawingUnderLineType.None) + { + switch (textRun._underLineType) + { + case eDrawingUnderLineType.Single: + underlineContent += "underline"; + break; + //These are all css only apparently + //case eUnderLineType.Double: + // fontStyleAttributes += "double"; + // break; + //case eUnderLineType.Dotted: + // fontStyleAttributes += "dotted"; + // break; + //case eUnderLineType.Dash: + // fontStyleAttributes += "dashed"; + // break; + //case eUnderLineType.Wavy: + // fontStyleAttributes += "wavy"; + // break; + default: + underlineContent += "underline"; + break; + //throw new NotImplementedException("Not implemented yet"); + } + if(textRun._underlineColor != System.Drawing.Color.Empty) + { + UnderlineColorString = $"{{1}}"; + } + content += underlineContent; + //Underline color + //We can change the underline color using double tspans + // SVG with a colored underlinesection. + } + + if (textRun._strikeType == eDrawingStrikeType.Single) + { + //Has to check if Both underline and strike + if (textRun._underLineType != eDrawingUnderLineType.None) + { + content += ","; + } + content += "line-through"; + } + + if(string.IsNullOrEmpty(content) == false) + { + if (string.IsNullOrEmpty(UnderlineColorString)) + { + fontStyleAttributes += $" text-decoration=\"{content}\" "; + } + else + { + UnderlineColorString = string.Format(UnderlineColorString, $"text-decoration: {content};", "{0}"); + } + } + } + return fontStyleAttributes; + } + + public override void Render(TextRunRenderItem textRun) + { + var sbStartidx = OutputStream.Length -1; + + string finalString = ""; + var xString = $"x =\"{(textRun.Bounds.Left.PointToPixelString())}\" "; + + var currentYEndPos = textRun.Bounds.Position.Y; // Global position Y + finalString += $"= textRun.ClippingHeight) + { + //visibility = " display=\"none\""; + } + finalString += visibility; + finalString += $"{GetFontStyleAttributes(textRun)}"; + + + if (textRun._measurementFont != null) + { + finalString += $"font-family=\"{textRun._measurementFont.Family}," + + $"{textRun._measurementFont.Family}_MSFontService,sans-serif\" " + + $"font-size=\"{fontSize.ToString(CultureInfo.InvariantCulture)}px\" "; + } + + if(string.IsNullOrEmpty(textRun.FillColor) == false) + { + finalString += $" style=\"fill: {textRun.FillColor};\" "; + } + + //Avoid rendering fill color as we do so via style + var temp = textRun.FillColor; + textRun.FillColor = null; + + var sb = new StringBuilder(); + sb.Append(finalString); + + //Get color etc. + //Renders up until this point (must be done to end the attribute addings so that text content can then be added) + RenderBaseToSpecified(textRun, sb); + + textRun.FillColor = temp; + + //Since final string has been written in base.render erase it. + finalString = ""; + + finalString += ">"; + //Add actual text content + finalString += textRun._currentText; + finalString += ""; + sb.Append(finalString); + + var textRunString = sb.ToString(); + + //Wrap in another tspan to apply underline color if neccesary + if (string.IsNullOrEmpty(UnderlineColorString) == false) + { + textRunString = string.Format(UnderlineColorString, textRunString); + } + + if (textRun is SvgTextRunRenderItem) + { + var tr = (SvgTextRunRenderItem)textRun; + if (tr.RenderTextNode) + { + textRunString = $"{textRunString}"; + } + } + + OutputStream.Append(textRunString); + UnderlineColorString = string.Empty; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Svg/SvgTitleRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/SvgTitleRenderer.cs new file mode 100644 index 0000000000..cb05caebef --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Svg/SvgTitleRenderer.cs @@ -0,0 +1,20 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using System.Globalization; +using System.Text; + +namespace EPPlus.DrawingRenderer.Svg +{ + public class SvgTitleRenderer : SvgBaseRenderer + { + public SvgTitleRenderer(StringBuilder outputStream) : base(outputStream) + { + + } + internal string Suffix = "px"; + public override void Render(TitleRenderItem item) + { + OutputStream.Append($"{item.Title}"); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/ColorExtensions.cs b/src/EPPlus.DrawingRenderer/Utils/ColorExtensions.cs new file mode 100644 index 0000000000..7dff7f14be --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/ColorExtensions.cs @@ -0,0 +1,13 @@ +using System.Drawing; + +namespace OfficeOpenXml.Utils +{ + internal static class ColorExtentions + { + internal static string To6CharHexString(this Color color) + { + return (color.ToArgb() & 0xFFFFFF).ToString("x6"); + } + } + +} diff --git a/src/EPPlus.DrawingRenderer/Utils/ColorUtils.cs b/src/EPPlus.DrawingRenderer/Utils/ColorUtils.cs new file mode 100644 index 0000000000..ee432122e7 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/ColorUtils.cs @@ -0,0 +1,54 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using System.Drawing; + +namespace EPPlusImageRenderer.Utils +{ + internal static class ColorUtils + { + internal static string To6CharHexStringImage(this Color color) + { + return (color.ToArgb() & 0xFFFFFF).ToString("x6"); + } + + internal static Color GetAdjustedColor(PathFillMode fillColorSource, Color fc) + { + switch (fillColorSource) + { + case PathFillMode.Darken: + fc = ApplyBlend(fc, Color.Black, 0.4); + break; + case PathFillMode.DarkenLess: + fc = ApplyBlend(fc, Color.Black, 50D/255D); + break; + case PathFillMode.LightenLess: + fc = ApplyBlend(fc, Color.White, 50D / 255D); + break; + case PathFillMode.Lighten: + fc = ApplyBlend(fc, Color.White, 0.4); + break; + } + + return fc; + } + internal static Color ApplyBlend(Color color, Color blendColor, double percent) + { + var colorPercent = 1 - percent; + var r = (int)Math.Min(255D, color.R * colorPercent + blendColor.R * percent); + var g = (int)Math.Min(255D, color.G * colorPercent + blendColor.G * percent); + var b = (int)Math.Min(255D, color.B * colorPercent + blendColor.B * percent); + return Color.FromArgb(0xff, r, g, b); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/ConvertUtil.cs b/src/EPPlus.DrawingRenderer/Utils/ConvertUtil.cs new file mode 100644 index 0000000000..b6d9150594 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/ConvertUtil.cs @@ -0,0 +1,507 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; +using System.Xml; +namespace EPPlus.DrawingRenderer.Utils +{ + internal static class ConvertUtil + { + static class ParseArguments + { + public static NumberStyles Number = NumberStyles.Float | NumberStyles.AllowThousands; + public static DateTimeStyles DateTime = DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal; + } + internal static bool IsNumericOrDate(object candidate) + { + if (candidate == null) return false; + var t = candidate.GetType(); + if (t.IsPrimitive) return true; + return t == typeof(decimal) || t == typeof(DateTime) || t == typeof(TimeSpan); + } + internal static bool IsNumeric(object candidate) + { + if (candidate == null) return false; + var t = candidate.GetType(); + if (t.IsPrimitive) return true; + return t == typeof(decimal); + } + internal static bool IsExcelNumeric(object candidate) + { + if (candidate == null) return false; + var t = candidate.GetType(); + if (t.IsPrimitive && t != typeof(bool)) return true; + return t == typeof(decimal) || t == typeof(DateTime) || t == typeof(TimeSpan); + } + + internal static bool IsNumericOrDate(object candidate, bool includeNumericString, bool includePercentageString) + { + if (IsNumericOrDate(candidate)) return true; + if (candidate != null) + { + if (includeNumericString && TryParseNumericString(candidate.ToString(), out double d, CultureInfo.CurrentCulture)) + { + return true; + } + else if (includePercentageString && IsPercentageString(candidate.ToString())) + { + return true; + } + } + return false; + } + + internal static bool IsPercentageString(string s) + { + if (string.IsNullOrEmpty(s)) return false; + s = s.Trim(); + if (s.Trim().EndsWith("%")) + { + var tmp = s; + int n = 0; + while (tmp.Length > 0 && tmp.Last() == '%') + { + tmp = tmp.Substring(0, tmp.Length - 1); + n++; + if (n > 1) + { + return false; + } + } + return double.TryParse(tmp, out double n2); + } + return false; + } + /// + /// Tries to parse a double from the specified which is expected to be a string value. + /// + /// The string value. + /// The double value parsed from the specified . + /// Other than Current culture + /// True if could be parsed to a double; otherwise, false. + internal static bool TryParseNumericString(string candidateString, out double numericValue, CultureInfo cultureInfo = null) + { + if (!string.IsNullOrEmpty(candidateString)) + { + return double.TryParse(candidateString, ParseArguments.Number, cultureInfo ?? CultureInfo.CurrentCulture, out numericValue); + } + numericValue = 0; + return false; + } + + internal static bool TryParsePercentageString(string s, out double numericValue, CultureInfo cultureInfo = null) + { + numericValue = 0; + if (string.IsNullOrEmpty(s)) return false; + s = s.Trim(); + if (s.Trim().EndsWith("%")) + { + var tmp = s; + while (tmp.Length > 0 && tmp.Last() == '%') + { + tmp = tmp.Substring(0, tmp.Length - 1); + } + if (TryParseNumericString(tmp, out numericValue, cultureInfo)) + { + numericValue /= 100d; + return true; + } + } + return false; + } + + /// + /// Tries to parse a boolean value from the specificed . + /// + /// The value to check for boolean-ness. + /// The boolean value parsed from the specified . + /// True if could be parsed + internal static bool TryParseBooleanString(string candidateString, out bool result) + { + if (!string.IsNullOrEmpty(candidateString)) + { + if (candidateString == "-1" || candidateString == "1") + { + result = true; + return true; + } + else if (candidateString == "0") + { + result = false; + return true; + } + else + { + return bool.TryParse(candidateString, out result); + } + } + result = false; + return false; + } + internal static bool ToBooleanString(string candidateString, bool defaultValue = false) + { + if (!string.IsNullOrEmpty(candidateString)) + { + if (candidateString == "-1" || candidateString == "1") + { + return true; + } + else if (candidateString == "0") + { + return false; + } + else + { + if (bool.TryParse(candidateString, out bool result)) + { + return result; + } + } + } + return defaultValue; + } + + /// + /// Tries to parse an int value from the specificed . + /// + /// The value to check for boolean-ness. + /// The boolean value parsed from the specified . + /// True if could be parsed + internal static bool TryParseIntString(string candidateString, out int result) + { + if (!string.IsNullOrEmpty(candidateString)) + return int.TryParse(candidateString, out result); + result = 0; + return false; + } + internal static int? GetValueIntNull(string s) + { + if (string.IsNullOrEmpty(s)) return null; + return int.Parse(s, CultureInfo.InvariantCulture); + } + internal static long? GetValueLongNull(string s) + { + if (string.IsNullOrEmpty(s)) return null; + return long.Parse(s, CultureInfo.InvariantCulture); + } + /// + /// Tries to parse a from the specified which is expected to be a string value. + /// + /// The string value. + /// The double value parsed from the specified . + /// True if could be parsed to a double; otherwise, false. + internal static bool TryParseDateString(string candidateString, out DateTime result) + { + if (!string.IsNullOrEmpty(candidateString)) + { + return DateTime.TryParse(candidateString, CultureInfo.CurrentCulture, ParseArguments.DateTime, out result); + } + result = DateTime.MinValue; + return false; + } + internal static double GetValueDouble(object v, bool ignoreBool, bool retNaN, bool includeStrings) + { + double d; + try + { + if (ignoreBool && v is bool) + { + return 0; + } + if (IsNumericOrDate(v)) + { + if (v is DateTime) + { + d = ((DateTime)v).ToOADate(); + } + else if (v is TimeSpan) + { + d = DateTime.FromOADate(0).Add((TimeSpan)v).ToOADate(); + } + else + { + d = Convert.ToDouble(v, CultureInfo.InvariantCulture); + } + } + else if (includeStrings && v != null) + { + if (TryParseNumericString(v.ToString(), out double val, CultureInfo.CurrentCulture)) + { + d = val; + } + else if (TryParsePercentageString(v.ToString(), out double percentage, CultureInfo.CurrentCulture)) + { + d = percentage; + } + else + { + d = retNaN ? double.NaN : 0; + } + } + else + { + d = retNaN ? double.NaN : 0; + } + } + + catch + { + d = retNaN ? double.NaN : 0; + } + return d; + } + internal static string ExcelEscapeString(string s) + { + return s.Replace("&", "&"). + Replace("<", "<"). + Replace(">", ">"); + } + internal static string HtmlEscapeString(string s) + { + return s.Replace("&", "&"). + Replace("<", "<"). + Replace(">", ">"). + Replace("\"", """). + Replace("'", "'"); + } + /// + /// Return true if preserve space attribute is set. + /// + /// + /// + /// + internal static void ExcelEncodeString(StreamWriter sw, string t) + { + if (Regex.IsMatch(t, "(_x[0-9A-Fa-f]{4,4}_)")) + { + var match = Regex.Match(t, "(_x[0-9A-Fa-f]{4,4}_)"); + int indexAdd = 0; + while (match.Success) + { + t = t.Insert(match.Index + indexAdd, "_x005F"); + indexAdd += 6; + match = match.NextMatch(); + } + } + for (int i = 0; i < t.Length; i++) + { + if (t[i] <= 0x1f && t[i] != '\t' && t[i] != '\n' && t[i] != '\r') //Not Tab, CR or LF + { + sw.Write("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X")); + } + else if (t[i] > 0xFFFD) + { + sw.Write($"_x{((int)t[i]).ToString("X")}_"); + } + else + { + sw.Write(t[i]); + } + } + + } + /// + /// Return true if preserve space attribute is set. + /// + /// + /// + /// + /// + internal static void ExcelEncodeString(StringBuilder sb, string t, bool encodeTabLF = false) + { + if (Regex.IsMatch(t, "(_x[0-9A-Fa-f]{4,4}_)")) + { + var matches = Regex.Matches(t, "(_x[0-9A-Fa-f]{4,4})"); + int indexAdd = 0; + foreach (Match m in matches) + { + t = t.Insert(m.Index + indexAdd, "_x005F"); + indexAdd += 6; + } + } + for (int i = 0; i < t.Length; i++) + { + if (t[i] <= 0x1f && + (t[i] != '\n' && t[i] != '\r' && t[i] != '\t' && encodeTabLF == false || //Not Tab, CR or LF + encodeTabLF)) + { + sb.AppendFormat("_x00{0}_", (t[i] <= 0xf ? "0" : "") + ((int)t[i]).ToString("X")); + } + else if (t[i] > 0xFFFD) + { + sb.Append($"_x{((int)t[i]).ToString("X")}_"); + } + else + { + sb.Append(t[i]); + } + } + } + internal static string ExcelEscapeAndEncodeString(string t, bool crLfEncode = true) + { + if (string.IsNullOrEmpty(t)) + { + return t; + } + return ExcelEncodeString(ExcelEscapeString(t), crLfEncode); + } + /// + /// Return true if preserve space attribute is set. + /// + /// + /// + /// + internal static string ExcelEncodeString(string t, bool crLfEncode = true) + { + StringBuilder sb = new StringBuilder(); + t = t.Replace("\r\n", "\n"); //For some reason can't table name have cr in them. Replace with nl + ExcelEncodeString(sb, t, crLfEncode); + return sb.ToString(); + } + internal static string ExcelDecodeString(string t) + { + if (string.IsNullOrEmpty(t)) return t; + var ret = new StringBuilder(); + + var ix = 0; + for (var i = 0; i < t.Length; i++) + { + var c = t[i]; + if (c == '\r') + { + ret.Append('\n'); + if (i + 1 < t.Length && t[i + 1] == '\n') + { + i++; + } + } + else + { + if (Matches(c, ref ix)) + { + if (ix == 7) + { + var encoded = t.Substring(i - 4, 4); + ret.Append((char)int.Parse(encoded, NumberStyles.AllowHexSpecifier)); + ix = 0; + } + } + else + { + if (ix > 0) + { + //If two underscores in a row the last one should count as potentially in matches + if (c == '_' && ix == 1) + { + ret.Append(t.Substring(i - ix, ix)); + } + else + { + ret.Append(t.Substring(i - ix, ix + 1)); + ix = 0; + } + } + else + { + ret.Append(c); + } + } + } + } + + if (ix > 0) + { + ret.Append(t.Substring(t.Length - ix, ix)); + } + + return ret.ToString(); + } + + private static bool Matches(char c, ref int ix) + { + if (ix == 0 && c == '_' || + ix == 1 && c == 'x' || + ix >= 2 && ix <= 5 && (c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f') || + c == '_' && ix == 6) + { + ix++; + return true; + } + else + { + return false; + } + } + + private static bool IsDate(object v, out DateTime date) + { + if (v is DateTime dt) + { + date = dt; + return true; + } +#if (NET6_0_OR_GREATER) + if (v is DateOnly dto) + { + date = dto.ToDateTime(TimeOnly.MinValue); + return true; + } +#endif + date = default; + return false; + } + private static bool IsTimeSpan(object v, out TimeSpan timeSpan) + { + if (v is TimeSpan ts) + { + timeSpan = ts; + return true; + } +#if (NET6_0_OR_GREATER) + if (v is TimeOnly to) + { + timeSpan = to.ToTimeSpan(); + return true; + } +#endif + timeSpan = default; + return false; + } + /// + /// Handles the issue with Excel having the incorrect values before 1900-03-01. Excel has 1900-02-29 as a valid value, but it does not exists in the calendar. Dates between 1900-02-28 and 1900-01-01 shuld be subtracted added 1 to the value. 0 in Excel is 1900-01-00 which is not valid in .NET. + /// + /// + /// + internal static DateTime FromOADateExcel(double d) + { + if (d < 0) + { + return DateTime.MinValue; + } + else if (d < 60) + { + d++; + } + return DateTime.FromOADate(d); + } + + #region internal cache objects + internal static TextInfo _invariantTextInfo = CultureInfo.InvariantCulture.TextInfo; + internal static CompareInfo _invariantCompareInfo = CompareInfo.GetCompareInfo(CultureInfo.InvariantCulture.Name); //TODO:Check that it works + #endregion + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/EnumUtils/EnumUtil.cs b/src/EPPlus.DrawingRenderer/Utils/EnumUtils/EnumUtil.cs new file mode 100644 index 0000000000..1ca2e9ec3b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/EnumUtils/EnumUtil.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.CompilerServices; + +namespace EPPlus.DrawingRenderer.Utils +{ + internal static class EnumUtil + { + +#if (!NET35) + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool HasFlag(T value, T flag) where T : Enum + { + return (Convert.ToInt32(value) & Convert.ToInt32(flag)) == Convert.ToInt32(flag); + } +#if (!NET35) + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool HasNotFlag(T value, T flag) where T : Enum + { + return (Convert.ToInt32(value) & Convert.ToInt32(flag)) != Convert.ToInt32(flag); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/EnumUtils/ExtensionFunctions.cs b/src/EPPlus.DrawingRenderer/Utils/EnumUtils/ExtensionFunctions.cs new file mode 100644 index 0000000000..229ca5bb9d --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/EnumUtils/ExtensionFunctions.cs @@ -0,0 +1,143 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace EPPlus.DrawingRenderer.Utils +{ + internal static class EnumExtensions + { + /// + /// Returns the enum value with first char lower case + /// + /// + /// + internal static string ToEnumString(this Enum enumValue) + { + var s = enumValue.ToString(); + return s.Substring(0, 1).ToLower() + s.Substring(1); + } + /// + /// Returns the enum value with first char lower case. + /// + /// + /// + /// + /// + internal static string ToEnumString(this Enum enumValue, T defaultValue) where T : Enum + { + if(enumValue.Equals(defaultValue)) + { + return null; + } + var s = enumValue.ToString(); + return s.Substring(0, 1).ToLower() + s.Substring(1); + } + /// + /// Returns the enum value with first char lower case. + /// + /// + /// + /// + /// + internal static string ToEnumString(this Enum enumValue, Dictionary lookup) where T : Enum + { + //if (enumValue.Equals(defaultValue)) + //{ + // return null; + //} + if(lookup.TryGetValue((T)enumValue, out string v)) + { + return v; + } + var s = enumValue.ToString(); + return s.Substring(0, 1).ToLower() + s.Substring(1); + } + + internal static T? ToEnum(this string s) where T : struct + { + try + { + if (string.IsNullOrEmpty(s)) return null; + if (!Enum.GetNames(typeof(T)).Any(x => x.Equals(s, StringComparison.OrdinalIgnoreCase))) + { + return null; + } + return (T)Enum.Parse(typeof(T), s, true); + } + catch + { + return null; + } + } + internal static T ToEnum(this string s, T defaultValue, Dictionary lookup) where T : struct + { + try + { + if (string.IsNullOrEmpty(s)) return defaultValue; + if(lookup.TryGetValue(s, out T v)) + { + return v; + } + if (!Enum.GetNames(typeof(T)).Any(x => x.Equals(s, StringComparison.OrdinalIgnoreCase))) + { + return defaultValue; + } + return (T)Enum.Parse(typeof(T), s, true); + } + catch + { + return defaultValue; + } + } + + internal static T ToEnum(this string s, T defaultValue) where T : struct + { + try + { + if (string.IsNullOrEmpty(s)) return defaultValue; + return (T)Enum.Parse(typeof(T), s, true); + } + catch + { + return defaultValue; + } + } + + internal static string GetStringValueForXml(this bool boolValue) + { + return boolValue ? "1" : "0"; + } + internal static bool IsInt(this string s) + { + return !s.Any(x => x < '0' && x > '9'); + } + internal static string ToColorString(this Color color) + { + return (color.ToArgb() & 0xFFFFFF).ToString("X").PadLeft(6, '0'); + } + internal static string GetXmlAttributeValue(this bool value, string attribute, bool? defaultValue) + { + if (value == defaultValue) + { + return ""; + } + else + { + return $" {attribute}=\"{(value ? "1" : "0")}\""; + } + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/ExtentionFunctions.cs b/src/EPPlus.DrawingRenderer/Utils/ExtentionFunctions.cs new file mode 100644 index 0000000000..809044fdeb --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/ExtentionFunctions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace EPPlus.DrawingRenderer.Utils +{ + internal static class ExtentionFunctions + { + internal static bool IsElementWithName(this XmlReader xr, string name) + { + return xr.NodeType == XmlNodeType.Element && xr.LocalName == name; + } + internal static bool IsEndElementWithName(this XmlReader xr, string name) + { + return xr.NodeType == XmlNodeType.EndElement && xr.LocalName == name; + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/MConverter.cs b/src/EPPlus.DrawingRenderer/Utils/MConverter.cs new file mode 100644 index 0000000000..fd2ccd93ab --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/MConverter.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Utils +{ + /// + /// Math converter utils + /// + internal static class MConverter + { + internal static double DegreesToRadians(double degree) + { + return degree * (Math.Round((double)System.Math.PI, 14) / 180); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/Utils/MathHelper.cs b/src/EPPlus.DrawingRenderer/Utils/MathHelper.cs new file mode 100644 index 0000000000..32a004fa6b --- /dev/null +++ b/src/EPPlus.DrawingRenderer/Utils/MathHelper.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace EPPlus.DrawingRenderer.Utils +{ + internal static class MathHelper + { + public static double Radians(double angle) + { + return (angle / 180) * Math.PI; + } + + internal static double Radians(object value) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/EPPlus.DrawingRenderer/enums/AdjustmentPointType.cs b/src/EPPlus.DrawingRenderer/enums/AdjustmentPointType.cs new file mode 100644 index 0000000000..30a67b4991 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/enums/AdjustmentPointType.cs @@ -0,0 +1,22 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer +{ + internal enum AdjustmentPointType + { + None = 0, + Linear = 1, + Radial = 2, + Angle = 3 + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/enums/PathDrawingType.cs b/src/EPPlus.DrawingRenderer/enums/PathDrawingType.cs new file mode 100644 index 0000000000..e5d2e6b72d --- /dev/null +++ b/src/EPPlus.DrawingRenderer/enums/PathDrawingType.cs @@ -0,0 +1,33 @@ +namespace EPPlus.DrawingRenderer +{ + /// + /// Drawing type + /// + public enum PathDrawingType + { + /// + /// Drawing-Path Move to command + /// + MoveTo, + /// + /// Drawing-Path Line to command + /// + LineTo, + /// + /// Drawing-Path Arc command + /// + ArcTo, + /// + /// Drawing-Path Cubic Berzier Curve command + /// + CubicBezierTo, + /// + /// Drawing-Path Quad Berier Curve command + /// + QuadBezierTo, + /// + /// Drawing-Path Close command + /// + Close + } +} diff --git a/src/EPPlus.DrawingRenderer/enums/PathFillMode.cs b/src/EPPlus.DrawingRenderer/enums/PathFillMode.cs new file mode 100644 index 0000000000..72b31929c4 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/enums/PathFillMode.cs @@ -0,0 +1,33 @@ +namespace EPPlus.DrawingRenderer +{ + /// + /// How a shape path is filled. + /// + public enum PathFillMode + { + /// + /// The corresponding path should have a normally shaded color applied to it’s fill + /// + Norm, + /// + /// The corresponding path should have a darker shaded color applied to it’s fill. + /// + Darken, + /// + /// The corresponding path should have a slightly darker shaded color applied to it’s fill. + /// + DarkenLess, + /// + /// The corresponding path should have a lightly shaded color applied to it’s fill. + /// + Lighten, + /// + /// The corresponding path should have a slightly lighter shaded color applied to it’s fill. + /// + LightenLess, + /// + /// The corresponding path should have no fill. + /// + None + } +} diff --git a/src/EPPlus.DrawingRenderer/enums/RenderItemType.cs b/src/EPPlus.DrawingRenderer/enums/RenderItemType.cs new file mode 100644 index 0000000000..dacc104f01 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/enums/RenderItemType.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer +{ + public enum RenderItemType + { + Path = 0, + Rect = 1, + Group = 2, + Line = 3, + Ellipse = 4, + Text = 5, + TextRun = 6, + Paragraph = 7, + CommentTitle = 8, + UseReference = 9, + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/enums/ShapeStyle.cs b/src/EPPlus.DrawingRenderer/enums/ShapeStyle.cs new file mode 100644 index 0000000000..7f47f1fda8 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/enums/ShapeStyle.cs @@ -0,0 +1,773 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace EPPlus.DrawingRenderer +{ + /// + /// Shape style + /// + public enum ShapeStyle + { + /// + /// Callout: with border and accent bar + /// + AccentBorderCallout1, + /// + /// Callout: with bent line and accent bar + /// + AccentBorderCallout2, + /// + /// Callout: with double bent line and accent bar + /// + AccentBorderCallout3, + /// + /// Callout: with line + /// + AccentCallout1, + /// + /// Callout: with bent line + /// + AccentCallout2, + /// + /// Callout: with double bent line + /// + AccentCallout3, + /// + /// Action button: Back < + /// + ActionButtonBackPrevious, + /// + /// Action button: Beginning |< + /// + ActionButtonBeginning, + /// + /// Action button: Blank + /// + ActionButtonBlank, + /// + /// Action button: with document icon + /// + ActionButtonDocument, + /// + /// Action button: End >| + /// + ActionButtonEnd, + /// + /// Action button: Next > + /// + ActionButtonForwardNext, + /// + /// Action button: Help ? + /// + ActionButtonHelp, + /// + /// Action button: Home icon + /// + ActionButtonHome, + /// + /// Action button: Information 🛈 + /// + ActionButtonInformation, + /// + /// Action button: Camera icon + /// + ActionButtonMovie, + /// + /// Action button: U-turn icon. + /// + ActionButtonReturn, + /// + /// Action button: Speaker icon + /// + ActionButtonSound, + /// + /// Arc: Quater circle + /// + Arc, + /// + /// A bent arrow + /// + BentArrow, + /// + /// Bent connector 2 + /// + BentConnector2, + /// + /// Bent connector 3 + /// + BentConnector3, + /// + /// Bent connector 4 + /// + BentConnector4, + /// + /// Bent connector 5 + /// + BentConnector5, + /// + /// A bent up arrow + /// + BentUpArrow, + /// + /// Bevel + /// + Bevel, + /// + /// Block arc: Half circle + /// + BlockArc, + /// + /// Callout: Line + /// + BorderCallout1, + /// + /// Callout: Bent line with border + /// + BorderCallout2, + /// + /// Callout: Double bent line with border. + /// + BorderCallout3, + /// + /// Brace pair: { } + /// + BracePair, + /// + /// Bracket pair: ( ) + /// + BracketPair, + /// + /// Callout: Line + /// + Callout1, + /// + /// Callout: Bent line + /// + Callout2, + /// + /// Callout: Double bent line + /// + Callout3, + /// + /// Can: A cylinder shape + /// + Can, + /// + /// A plus within a rectangle + /// + ChartPlus, + /// + /// A star within a rectangle + /// + ChartStar, + /// + /// A x within a rectangle + /// + ChartX, + /// + /// Cheveron: > + /// + Chevron, + /// + /// Chord: The quarter of a circle. + /// + Chord, + /// + /// A cirular arrow. + /// + CircularArrow, + /// + /// A cloud + /// + Cloud, + /// + /// Callout: Cloud + /// + CloudCallout, + /// + /// Corner: L + /// + Corner, + /// + /// Corner Tabs: Triangle in the corners. + /// + CornerTabs, + /// + /// A 3D cube shape. + /// + Cube, + /// + /// Curved Connector 2 + /// + CurvedConnector2, + /// + /// Curved Connector 3 + /// + CurvedConnector3, + /// + /// Curved Connector 4 + /// + CurvedConnector4, + /// + /// Curved Connector 5 + /// + CurvedConnector5, + /// + /// Curved Arrow: Down + /// + CurvedDownArrow, + /// + /// Curved Arrow: Left + /// + CurvedLeftArrow, + /// + /// Curved Arrow: Right + /// + CurvedRightArrow, + /// + /// Curved Arrow: Up + /// + CurvedUpArrow, + /// + /// A decagon: 10 corners + /// + Decagon, + /// + /// A diagonal stripe + /// + DiagStripe, + /// + /// A diamond shape + /// + Diamond, + /// + /// A Dodecagon: 12 corners + /// + Dodecagon, + /// + /// A donut shape + /// + Donut, + /// + /// Double wave + /// + DoubleWave, + /// + /// A down arrow + /// + DownArrow, + /// + /// Callout: Down arrow + /// + DownArrowCallout, + /// + /// An ellipse + /// + Ellipse, + /// + /// Ellipse ribbon: point up + /// + EllipseRibbon, + /// + /// Ellipse ribbon: point down + /// + EllipseRibbon2, + /// + /// Flow chart: + /// + FlowChartAlternateProcess, + /// + /// Flow chart: Collate + /// + FlowChartCollate, + /// + /// Flow chart: Connector + /// + FlowChartConnector, + /// + /// Flow chart: Decision + /// + FlowChartDecision, + /// + /// Flow chart: Delay + /// + FlowChartDelay, + /// + /// Flow chart: Display + /// + FlowChartDisplay, + /// + /// Flow chart: Document + /// + FlowChartDocument, + /// + /// Flow chart: Extract + /// + FlowChartExtract, + /// + /// Flow chart: Input/Output Data + /// + FlowChartInputOutput, + /// + /// Flow chart: Internal Storage + /// + FlowChartInternalStorage, + /// + /// Flow chart: Magnetic Disk + /// + FlowChartMagneticDisk, + /// + /// Flow chart: Magnetic Drum + /// + FlowChartMagneticDrum, + /// + /// Flow chart: Magnetic Tape + /// + FlowChartMagneticTape, + /// + /// Flow chart: Manual Input + /// + FlowChartManualInput, + /// + /// Flow chart: Manual Operation + /// + FlowChartManualOperation, + /// + /// Flow chart: Chart Merge + /// + FlowChartMerge, + /// + /// Flow chart: Multi document + /// + FlowChartMultidocument, + /// + /// Flow chart: Offline Storage + /// + FlowChartOfflineStorage, + /// + /// Flow chart: Offpage Connector + /// + FlowChartOffpageConnector, + /// + /// Flow chart: Online Storage + /// + FlowChartOnlineStorage, + /// + /// Flow chart: Or + /// + FlowChartOr, + /// + /// Flow chart: Predefined Process + /// + FlowChartPredefinedProcess, + /// + /// Flow chart: Preparation + /// + FlowChartPreparation, + /// + /// Flow chart: Process + /// + FlowChartProcess, + /// + /// Flow chart: Punched Card + /// + FlowChartPunchedCard, + /// + /// Flow chart: Punched Tape + /// + FlowChartPunchedTape, + /// + /// Flow chart: Sort + /// + FlowChartSort, + /// + /// Flow chart: Summing Junction + /// + FlowChartSummingJunction, + /// + /// Flow chart: Terminator + /// + FlowChartTerminator, + /// + /// Folded corner, right bottom + /// + FoldedCorner, + /// + /// A frame + /// + Frame, + /// + /// A Funnel + /// + Funnel, + /// + /// Gear, six cogs + /// + Gear6, + /// + /// Gear, nine cogs + /// + Gear9, + /// + /// Half frame. + /// + HalfFrame, + /// + /// A heart + /// + Heart, + /// + /// A Heptagon, 7 corners + /// + Heptagon, + /// + /// A Hexagon, 6 corners + /// + Hexagon, + /// + /// Home plate + /// + HomePlate, + /// + /// A horizontal scroll + /// + HorizontalScroll, + /// + /// Explosion 12 + /// + IrregularSeal1, + /// + /// Explosion 14 + /// + IrregularSeal2, + /// + /// Left arrow + /// + LeftArrow, + /// + /// Callout: Left arrow + /// + LeftArrowCallout, + /// + /// Left brace: { + /// + LeftBrace, + /// + /// Left bracket: ( + /// + LeftBracket, + /// + /// Left circular arrow + /// + LeftCircularArrow, + /// + /// Left Right arrow + /// + LeftRightArrow, + /// + /// Callout: Left rightd arrow + /// + LeftRightArrowCallout, + /// + /// Left right circular arrow + /// + LeftRightCircularArrow, + /// + /// Left right ribbon + /// + LeftRightRibbon, + /// + /// Left right up arrow + /// + LeftRightUpArrow, + /// + /// Left up arrow + /// + LeftUpArrow, + /// + /// Lightning bold + /// + LightningBolt, + /// + /// A line, from top-left to bottom-right. + /// + Line, + /// + /// An inverted line, from top-right to bottom-left. + /// + LineInv, + /// + /// Math: Divide ÷ + /// + MathDivide, + /// + /// Math: Equal = + /// + MathEqual, + /// + /// Math: Minus - + /// + MathMinus, + /// + /// Math: Multiply x + /// + MathMultiply, + /// + /// Math: Not equal ≠ + /// + MathNotEqual, + /// + /// Math: Plus + + /// + MathPlus, + /// + /// Half moon + /// + Moon, + /// + /// Non Isosceles Trapezoid + /// + NonIsoscelesTrapezoid, + /// + /// No smoking, circle with line + /// + NoSmoking, + /// + /// Notched Right Arrow + /// + NotchedRightArrow, + /// + /// Octagon, 8 corners + /// + Octagon, + /// + /// Parallelogram + /// + Parallelogram, + /// + /// Pentagon, 5 corners + /// + Pentagon, + /// + /// Pie + /// + Pie, + /// + /// Pie wedge + /// + PieWedge, + /// + /// Plaque + /// + Plaque, + /// + /// PlaqueTabs, inverted Plaque + /// + PlaqueTabs, + /// + /// A plus + /// + Plus, + /// + /// Quad Arrow + /// + QuadArrow, + /// + /// Callout: Quad Arrow + /// + QuadArrowCallout, + /// + /// A rectangle + /// + Rect, + /// + /// A ribbon - up + /// + Ribbon, + /// + /// Ribbon - down + /// + Ribbon2, + /// + /// Right arrow + /// + RightArrow, + /// + /// Callout: Right arrow + /// + RightArrowCallout, + /// + /// Right Brace } + /// + RightBrace, + /// + /// Right bracket ) + /// + RightBracket, + /// + /// Rectangle - rounded top-right + /// + Round1Rect, + /// + /// Rectangle - Round top-left and bottom-right + /// + Round2DiagRect, + /// + /// Rectangle - Round top corners + /// + Round2SameRect, + /// + /// Rectangle with rounded corners + /// + RoundRect, + /// + /// Right triangle + /// + RtTriangle, + /// + /// Smiley face + /// + SmileyFace, + /// + /// Rectangle, snipped top-right + /// + Snip1Rect, + /// + /// Rectangle, snipped top-right bottom-left + /// + Snip2DiagRect, + /// + /// Rectangle, snipped top + /// + Snip2SameRect, + /// + /// Rectangle, snipped top-left, rounded top-right + /// + SnipRoundRect, + /// + /// Square, tabs + /// + SquareTabs, + /// + /// Star, 10 + /// + Star10, + /// + /// Star, 12 + /// + Star12, + /// + /// Star, 16 + /// + Star16, + /// + /// Star, 24 + /// + Star24, + /// + /// Star, 32 + /// + Star32, + /// + /// Star, 4 + /// + Star4, + /// + /// Star, 5 + /// + Star5, + /// + /// Star, 6 + /// + Star6, + /// + /// Star, 7 + /// + Star7, + /// + /// Star, 8 + /// + Star8, + /// + /// Streight connector + /// + StraightConnector1, + /// + /// Striped right arrow + /// + StripedRightArrow, + /// + /// Sun + /// + Sun, + /// + /// Swoosh arrow + /// + SwooshArrow, + /// + /// A tear drop + /// + Teardrop, + /// + /// Trapezoid + /// + Trapezoid, + /// + /// Triangle + /// + Triangle, + /// + /// Up Arrow + /// + UpArrow, + /// + /// Callout: Up arrow + /// + UpArrowCallout, + /// + /// Up-down arrow + /// + UpDownArrow, + /// + /// Callout: Up-down arrow + /// + UpDownArrowCallout, + /// + /// U-turn arrow + /// + UturnArrow, + /// + /// A wave + /// + Wave, + /// + /// Callout Wedge: Ellipse + /// + WedgeEllipseCallout, + /// + /// Callout Wedge: Rectangle + /// + WedgeRectCallout, + /// + /// Callout Wedge: Rounded rectangle + /// + WedgeRoundRectCallout, + /// + /// Vertical scroll + /// + VerticalScroll, + /// + /// This is a custom shape defined by in the + /// + CustomShape + } +} \ No newline at end of file diff --git a/src/EPPlus.DrawingRenderer/resource/presetShapeDefinitions.xml b/src/EPPlus.DrawingRenderer/resource/presetShapeDefinitions.xml new file mode 100644 index 0000000000..d712b23625 --- /dev/null +++ b/src/EPPlus.DrawingRenderer/resource/presetShapeDefinitions.xml @@ -0,0 +1,19870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj new file mode 100644 index 0000000000..37ce84a67b --- /dev/null +++ b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + latest + enable + True + true + EPPlus.Export.Pdf.Tests.snk + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.snk b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.snk new file mode 100644 index 0000000000..8700e294be Binary files /dev/null and b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.snk differ diff --git a/src/EPPlus.Export.Pdf.Tests/MSTestSettings.cs b/src/EPPlus.Export.Pdf.Tests/MSTestSettings.cs new file mode 100644 index 0000000000..aaf278c844 --- /dev/null +++ b/src/EPPlus.Export.Pdf.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs new file mode 100644 index 0000000000..6ce9e4da3e --- /dev/null +++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs @@ -0,0 +1,292 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Settings; +using OfficeOpenXml.Export.PdfExport; +using EPPlus.Export.Pdf.Settings.PdfPageSizes; +using EPPlus.Export.Pdf; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using OfficeOpenXml; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Style; +using System.Diagnostics; + +namespace EPPlusTest.PDF +{ + [TestClass] + public class PdfTests : TestBase + { + /* BIG PDF TODO + * + * Missing Features: + * Embedding pictures as drawings + * Embedding pictures as cell content + * Embedding pictures as header/footer + * Number formatting + * Scaling document + * Conditional Formatting icons + * Vertical text + * Equations + * Pivot tables + * Shapes + * Charts + * 3D models + * Compression + * + * Bugs: + * Merged cell uses full width/height even when columns/rows are hidden. + * Conditional formatting not worksing 100% of the time. + * Table could sometimes select wrong style + * + * Other + * Cells: Remove stroke from solid fill and adjust size and position of cell more precise and only use fill command. + * Gradients: Make diamond gradients instead of radial gradtient in from corner and center gradient + * Text: Set up to use back up techniques when not embedding font + * Borders: Adjust and make border look better + * + */ + + /// + /// Old Test + /// + //[TestMethod] + //public void TestWritePdf() + //{ + // using var p = OpenTemplatePackage("PDFTest.xlsx"); + // //using var p = OpenTemplatePackage("PdfGrids\\PdfTextTest.xlsx"); + // //using var p = OpenTemplatePackage("PdfGrids\\PdfPageBreakTest.xlsx"); + // //using var p = OpenTemplatePackage("PDFTest - Copy (2).xlsx"); + // //using var p = OpenTemplatePackage("PdfBorders.xlsx"); + // //using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells.xlsx"); + // //using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells Merged.xlsx"); + // //using var p = OpenTemplatePackage("Gradient.xlsx"); + // //using var p = OpenTemplatePackage("PatternFill.xlsx"); + // var ws = p.Workbook.Worksheets[0]; + // //var ws = p.Workbook.Worksheets[1]; + // PdfPageSettings pageSettings = new PdfPageSettings(); + // pageSettings.ShowGridLines = true; + // pageSettings.PageSize = PdfPageSize.A4; + // pageSettings.Orientation = Orientations.Portrait; + // pageSettings.Margins = PdfMargins.Normal; + // pageSettings.ShowGridLines = true; + // pageSettings.CenterOnPageHorizontally = true; + // pageSettings.CenterOnPageVertically = true; + // pageSettings.ShowHeadings = true; + // pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; + // //Debug Flags + // pageSettings.Debug = true; + // pageSettings.PrintAsText = true; + + // ExcelPdf pedeef = new ExcelPdf(ws, pageSettings); + // pedeef.CreatePdf("c:\\epplustest\\pdf\\FullPageTest49.pdf"); + //} + + /// + /// Old Test + /// + //[TestMethod] + //public void TestWritePdf2() + //{ + // using var p = OpenTemplatePackage("PDFTest2.xlsx"); + // PdfPageSettings pageSettings = new PdfPageSettings(); + // pageSettings.ShowGridLines = true; + // pageSettings.PageSize = PdfPageSize.A4; + // pageSettings.Orientation = Orientations.Portrait; + // pageSettings.Margins = PdfMargins.Normal; + // pageSettings.ShowGridLines = true; + // //Debug Flags + // pageSettings.Debug = true; + // pageSettings.PrintAsText = true; + + // ExcelPdf pedeef = new ExcelPdf(p.Workbook.Worksheets.First(), pageSettings); + // pedeef.CreatePdf("c:\\epplustest\\pdf\\EmojiTest.pdf"); + //} + + [TestMethod] + public void ReadPrintAreas() + { + //using var p = OpenTemplatePackage("PdfPrintAreas.xlsx"); + using var p = OpenTemplatePackage("PDFTest.xlsx"); + //using var p = OpenTemplatePackage("PDFTest_old.xlsx"); + //using var p = OpenTemplatePackage("DoubleBorder.xlsx"); + var ws = p.Workbook.Worksheets[0]; + PdfPageSettings pageSettings = new PdfPageSettings(); + pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; + pageSettings.CellErrors = CellErrors.NA; + pageSettings.Debug = true; + pageSettings.PrintAsText = true; + pageSettings.ShowGridLines = true; + pageSettings.ShowHeadings = true; + PdfCatalog catlog = new PdfCatalog(pageSettings, ws, "C:\\epplustest\\pdf\\FullPageTest58.pdf"); + + //line breaks + //wrap comments + //text placement + //alignment + //vertical + } + + [TestMethod] + public void PerfTest() + { + var sw = new Stopwatch(); + Console.WriteLine("Starting..."); + sw.Start(); + using var p = OpenTemplatePackage("Aico_0105_S_ALR_87011990_AICO_ASSET_ITE_2025-04_BS.xlsx"); + Console.WriteLine($"Read package time elapsed: {sw.ElapsedMilliseconds} ms"); + sw.Restart(); + var ws = p.Workbook.Worksheets[0]; + var dun = ws.Dimension; + var pageSettings = new PdfPageSettings + { + CommentsAndNotes = CommentsAndNotes.AtEndOfSheet, + CellErrors = CellErrors.NA, + Debug = true, + PrintAsText = true, + ShowGridLines = false, + ShowHeadings = true + }; + PdfCatalog catalog = new PdfCatalog(pageSettings, ws, "C:\\epplustest\\pdf\\OutputTest1.3.pdf"); + Console.WriteLine($"workbook exported time elapsed: {sw.ElapsedMilliseconds} ms"); + } + + + [TestMethod] + // works as expected. + //[DataRow("PDFTest.xlsx", "C:\\epplustest\\pdf\\FullPageTest56.pdf", "Sheet1")] + [DataRow("Aico_0105_S_ALR_87011990_AICO_ASSET_ITE_2025-04_BS.xlsx", "C:\\epplustest\\pdf\\OutputTest1.1.pdf", "SAP Data")] + + // Output file: OutputTest1.2.pdf + // 1. Minus signs alignment in cells differs from Excel. ------------------------------------------------ Comment: Currently no support for number formats. Requires implementing number formats. + // 2. Dimension seems to differ from Excel, Excel stops at row 75, EPPlus goes to row 89. --------------- Fixed + // 3. Row headings are sligthly wider in EPPlus than in Excel. ------------------------------------------ Fixed + [DataRow("Aico_0105_S_ALR_87011990_AICO_ASSET_ITE_2025-04_BS.xlsx", "C:\\epplustest\\pdf\\OutputTest1.2.pdf", "Summary")] + // works as expected + [DataRow("Aico WiP 120180 FBL3N for 0110 in 2025-04.xlsx", "C:\\epplustest\\pdf\\OutputTest1.4.pdf", "Technical")] + [DataRow("Aico KKS1 Variance Calculation for 0105 in 2025-04 (25_4_2025 15_43_40) .xlsx", "C:\\epplustest\\pdf\\OutputTest1.5.pdf", "Technical")] + + // Output file: OutputTest1.6.pdf + // 1. Merged cells not working ------------------------------------ Fixed. Comment Merged cells was fine, it was borders being rendered inside merged cells. + // 2. Pattern fills looks differnt, in some cases not working ----- + // 3. Rotation of text in cells not working (the dates). ---------- + // [DataRow("R05.xlsx", "C:\\epplustest\\pdf\\OutputTest1.6.pdf", "R05 Arbeitseinteilung")] + [DataRow("R05 - Copy.xlsx", "C:\\epplustest\\pdf\\OutputTest1.6.pdf", "R05 Arbeitseinteilung")] + //[DataRow("PatternStyles.xlsx", "C:\\epplustest\\pdf\\OutputTest1.8.pdf", "Sheet1")] + public void WorkbookTests(string sourceFile, string outputPath, string wsName) + { + using var p = OpenTemplatePackage(sourceFile); + var ws = p.Workbook.Worksheets[wsName]; + var d = ws.Dimension; + var d2 = ws.DimensionByValue; + + PdfPageSettings pageSettings = new PdfPageSettings(); + pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; + + pageSettings.CellErrors = CellErrors.Displayed; + pageSettings.Debug = true; + pageSettings.PrintAsText = true; + pageSettings.ShowGridLines = false; + pageSettings.ShowHeadings = false; + + PdfCatalog catalog = new PdfCatalog(pageSettings, ws, outputPath); + } + + /// + /// This test we can make somehing of. + /// + //[TestMethod] + //public void CalculatePages() + //{ + // using var p = new ExcelPackage(); + // var ws = p.Workbook.Worksheets.Add("Sheet 1"); + // PdfPageSettings pageSettings = new PdfPageSettings(); + // pageSettings.ShowHeadings = true; + // PdfWorksheet pws = new PdfWorksheet(); + // pws.Worksheet = ws; + // pws.ZeroCharWidth = PdfWorksheet.GetThemeFont0Width(ws); + // pws.ToRow = 256; + // PdfRange range = new PdfRange(); + // range.TotalWidth = 800; + // range.TotalHeight = 1600; + + // var result = PdfLayout.GetNumberOfPages(pageSettings, pws, ref range); + //} + + /// + /// Old Test + /// + //[TestMethod] + //public void TestWrapText() + //{ + // using var p = OpenTemplatePackage("PDFTest.xlsx"); + // var cell = p.Workbook.Worksheets[0].Cells["P118"]; + + // List TextFragments = GetTextFragments(cell.RichText).Cast().ToList(); + + + // var layout = OpenTypeFonts.GetTextLayoutEngineForFont((IFontFormatBase)TextFragments[0].RichTextOptions); + + // var TextLines = layout.WrapRichTextLineCollection(TextFragments, 51d); + //} + + //private static List GetTextFragments(ExcelRichTextCollection RichTextCollection, PdfCellStyle cellStyle = null) + //{ + // var textFragments = new List(); + // bool bold = false, italic = false, underline = false, strike = false; + // ExcelUnderLineType underLineType = ExcelUnderLineType.None; + // if (cellStyle != null && cellStyle.dxfFont != null) + // { + // bold = cellStyle.dxfFont.Bold != null ? (bool)cellStyle.dxfFont.Bold : false; + // italic = cellStyle.dxfFont.Italic != null ? (bool)cellStyle.dxfFont.Italic : false; + // strike = cellStyle.dxfFont.Strike != null ? (bool)cellStyle.dxfFont.Strike : false; + // underline = cellStyle.dxfFont.Underline != null; + // underLineType = cellStyle.dxfFont.Underline != null ? (ExcelUnderLineType)cellStyle.dxfFont.Underline : ExcelUnderLineType.None; + // } + // for (int i = 0; i < RichTextCollection.Count; i++) + // { + // var rt = RichTextCollection[i]; + // var textFrag = new TextFragment(); + // textFrag.Text = rt.Text; + + // textFrag.Font.Family = rt.FontName; + // textFrag.Font.Size = rt.Size; + + // textFrag.RichTextOptions.Bold = rt.Bold || bold; + // textFrag.RichTextOptions.Italic = rt.Italic || italic; + // //underline + // //none : 12 + // //single : 13 + // //Double : 4 + // //accouting does not exsist + // textFrag.RichTextOptions.UnderlineType = 12; + // textFrag.RichTextOptions.UnderlineType = rt.UnderLineType == ExcelUnderLineType.Single ? 13 : textFrag.RichTextOptions.UnderlineType; + // textFrag.RichTextOptions.UnderlineType = rt.UnderLineType == ExcelUnderLineType.Double ? 4 : textFrag.RichTextOptions.UnderlineType; + // textFrag.RichTextOptions.StrikeType = rt.Strike || strike ? 2 : 1; + // textFrag.RichTextOptions.SuperScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Superscript; + // textFrag.RichTextOptions.SubScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Subscript; + // textFrag.RichTextOptions.FontColor = rt.Color; + + // //Should no longer be neccesary + // //textFrag.Font.Style = (textFrag.RichTextOptions.Bold ? MeasurementFontStyles.Bold : 0) | + // // (textFrag.RichTextOptions.Italic ? MeasurementFontStyles.Italic : 0) | + // // (textFrag.RichTextOptions.UnderlineType != 12 ? MeasurementFontStyles.Underline : 0) | + // // (textFrag.RichTextOptions.StrikeType > 1 ? MeasurementFontStyles.Strikeout : 0); + + + // textFragments.Add(textFrag); + // } + + // return textFragments; + //} + } +} diff --git a/src/EPPlus.Export.Pdf.Tests/publickey.snk b/src/EPPlus.Export.Pdf.Tests/publickey.snk new file mode 100644 index 0000000000..3e29eb5bee Binary files /dev/null and b/src/EPPlus.Export.Pdf.Tests/publickey.snk differ diff --git a/src/EPPlus.Export.Pdf/AssemblyInfo.cs b/src/EPPlus.Export.Pdf/AssemblyInfo.cs new file mode 100644 index 0000000000..280655fcc7 --- /dev/null +++ b/src/EPPlus.Export.Pdf/AssemblyInfo.cs @@ -0,0 +1,35 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// In SDK-style projects such as this one, several assembly attributes that were historically +// defined in this file are now automatically added during build and populated with +// values defined in project properties. For details of which attributes are included +// and how to customise this process see: https://aka.ms/assembly-info-properties + + +// Setting ComVisible to false makes the types in this assembly not visible to COM +// components. If you need to access a type in this assembly from COM, set the ComVisible +// attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM. +[assembly: AllowPartiallyTrustedCallers] +[assembly: Guid("60855b7d-19da-4dfa-90b2-78231d227d65")] +[assembly: InternalsVisibleTo("EPPlus, PublicKey=00240000048000009400000006020000002400005253413100040000010001002981343969ed86fe604c56a84c61e33109424ef07bb458ff12e9533c11ea23ac8ef7e014b2a2de4ceb5f7528f963c755fe9b32f09cc35d21de94319d2a952a6e663cd46d6d98465998c77b52093d4f17cdc20ec054751244696f08afa6f4417d85267b147b73b6a3f5e9015b9dfd3dcc3328ce63df53a7c08a5544c1526ea5a5")] +[assembly: InternalsVisibleTo("EPPlus.Export.Pdf.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100dd3a3466a88cbf5d374fe992cec433c48022414fe96608933e8e36782001213dd31bc454dc6f962a54a3a76cfb9e03a32cd4c658ecd49d1a98709971a080ab92d5c5b65346155f8d6422db4ffbf662f78913996a9a8b78ee11ff3cda7e585208cd4468fb3201f15bbb1dfc45c120703c9d6ad495bb9de66893ae5ab5ac8f40dc")] +// +[assembly: InternalsVisibleTo("EPPlus.PdfExportPerformance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f5398d389a44aacee243c9e73152fae942e9ede958ebd4b06651a749e6b2c0395a66bc0fc133dce1cf83cd667fe8f761b433063e603968f12b0b17e474233410f8fe933853d2344e89526414ef65ed7236a7a5c012e30275ec30d7fb665dbe1bd3435439bec55f431b9e69e943294fd474942d6bcb431c94ef653cbeee5b8a9e")] diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/ExcelPatternMask.cs b/src/EPPlus.Export.Pdf/DocumentObjects/ExcelPatternMask.cs new file mode 100644 index 0000000000..4ff9734381 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/ExcelPatternMask.cs @@ -0,0 +1,307 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + /// + /// The cell fill pattern types EPPlus renders in the PDF export, matching + /// the names of OfficeOpenXml.Style.ExcelFillStyle. The pattern geometry is + /// taken from how Microsoft Excel itself rasterises each pattern when it + /// exports to PDF (an 8x8 tile), NOT from the ECMA-376 ST_Shd masks. Excel + /// and ST_Shd only overlap for a few patterns; since the goal is visual + /// parity with Excel, Excel's own output is the reference. + /// + internal enum ExcelPatternMask + { + DarkGray, + MediumGray, + LightGray, + Gray125, + Gray0625, + DarkHorizontal, + DarkVertical, + DarkDown, + DarkUp, + DarkGrid, + DarkTrellis, + LightHorizontal, + LightVertical, + LightDown, + LightUp, + LightGrid, + LightTrellis, + } + + /// + /// Reference catalog of the 8x8 cell fill pattern masks, transcribed from the + /// bitmaps Microsoft Excel produces when exporting each pattern fill to PDF. + /// + /// IMPORTANT - polarity and orientation: + /// + /// byte 1 == background == the cell fill background color. + /// byte 0 == foreground == the pattern color. + /// + /// So it is the 0 cells that get painted with the foreground/pattern color, + /// matching the convention used by the ECMA ST_Shd reference data. + /// + /// Row order matches the source bitmap exactly: row 0 is the TOP row. PDF + /// content streams have the origin at the bottom-left with y increasing + /// upward, so any comparison against rendered PDF output (or generation of a + /// PDF content stream) must mirror in y (row r maps to PDF y = 7 - r). That + /// y-flip is intentionally NOT applied here - the data is kept in bitmap + /// orientation and the flip is the responsibility of the render/diff step. + /// + internal static class ExcelPatternMaskData + { + private static readonly Dictionary _masks = BuildMasks(); + + /// + /// Gets the 8x8 reference mask for the given pattern. + /// Indexed as [row, column] with row 0 = top, matching the source bitmap. + /// + /// The pattern to look up. + /// An 8x8 matrix where 1 = background and 0 = foreground. + public static byte[,] GetMask(ExcelPatternMask pattern) + { + return _masks[pattern]; + } + + private static Dictionary BuildMasks() + { + var masks = new Dictionary(); + + // DarkGray (75 gray) + masks.Add(ExcelPatternMask.DarkGray, new byte[,] + { + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 0, 1, 0, 1, 0 }, + }); + + // MediumGray (50 gray) + masks.Add(ExcelPatternMask.MediumGray, new byte[,] + { + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + }); + + // LightGray (25 gray) + masks.Add(ExcelPatternMask.LightGray, new byte[,] + { + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 1, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + }); + + // Gray125 (12,5 gray) + masks.Add(ExcelPatternMask.Gray125, new byte[,] + { + { 0, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + }); + + // Gray0625 (6,25 gray) + masks.Add(ExcelPatternMask.Gray0625, new byte[,] + { + { 0, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + }); + + // DarkHorizontal (Horizontal stripe) + masks.Add(ExcelPatternMask.DarkHorizontal, new byte[,] + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + }); + + // DarkVertical (Vertical stripe) + masks.Add(ExcelPatternMask.DarkVertical, new byte[,] + { + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + }); + + // DarkDown (Reverse diagonal stripe) + masks.Add(ExcelPatternMask.DarkDown, new byte[,] + { + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 1, 0, 0, 0, 0, 1, 1, 1 }, + { 1, 1, 0, 0, 0, 0, 1, 1 }, + { 1, 1, 1, 0, 0, 0, 0, 1 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 1, 1, 1, 1, 0 }, + }); + + // DarkUp (Diagonal stripe) + masks.Add(ExcelPatternMask.DarkUp, new byte[,] + { + { 1, 1, 0, 0, 0, 0, 1, 1 }, + { 1, 0, 0, 0, 0, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 1, 1, 1, 1, 0 }, + { 0, 0, 1, 1, 1, 1, 0, 0 }, + { 0, 1, 1, 1, 1, 0, 0, 0 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + { 1, 1, 1, 0, 0, 0, 0, 1 }, + }); + + // DarkGrid (Diagonal crosshatch) + masks.Add(ExcelPatternMask.DarkGrid, new byte[,] + { + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 0, 0, 0, 0 }, + }); + + // DarkTrellis (Thick diagonal crosshatch) + masks.Add(ExcelPatternMask.DarkTrellis, new byte[,] + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 1 }, + { 1, 1, 0, 0, 0, 0, 1, 1 }, + { 1, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 1, 1, 0, 0, 0 }, + }); + + // LightHorizontal (Thin horizontal stripe) + masks.Add(ExcelPatternMask.LightHorizontal, new byte[,] + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + }); + + // LightVertical (Thin vertical stripe) + masks.Add(ExcelPatternMask.LightVertical, new byte[,] + { + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + }); + + // LightDown (Thin reverse diagonal stripe) + masks.Add(ExcelPatternMask.LightDown, new byte[,] + { + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 1, 0, 0, 1, 1, 1, 1, 1 }, + { 1, 1, 0, 0, 1, 1, 1, 1 }, + { 1, 1, 1, 0, 0, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 0, 1, 1 }, + { 1, 1, 1, 1, 1, 0, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 0, 0 }, + { 0, 1, 1, 1, 1, 1, 1, 0 }, + }); + + // LightUp (Thin diagonal stripe) + masks.Add(ExcelPatternMask.LightUp, new byte[,] + { + { 1, 1, 1, 0, 0, 1, 1, 1 }, + { 1, 1, 0, 0, 1, 1, 1, 1 }, + { 1, 0, 0, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 0 }, + { 1, 1, 1, 1, 1, 1, 0, 0 }, + { 1, 1, 1, 1, 1, 0, 0, 1 }, + { 1, 1, 1, 1, 0, 0, 1, 1 }, + }); + + // LightGrid (Thin horizontal crosshatch) + masks.Add(ExcelPatternMask.LightGrid, new byte[,] + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 1, 1, 1 }, + }); + + // LightTrellis (Thin diagonal crosshatch) + masks.Add(ExcelPatternMask.LightTrellis, new byte[,] + { + { 0, 0, 1, 0, 0, 1, 1, 1 }, + { 1, 0, 0, 0, 1, 1, 1, 1 }, + { 1, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 1, 0, 0, 1, 1, 1 }, + { 0, 1, 1, 1, 0, 0, 1, 0 }, + { 1, 1, 1, 1, 1, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 0, 0, 0 }, + { 0, 1, 1, 1, 0, 0, 1, 0 }, + }); + return masks; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/CIDSystemInfo.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/CIDSystemInfo.cs new file mode 100644 index 0000000000..49a6506dae --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/CIDSystemInfo.cs @@ -0,0 +1,21 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class CIDSystemInfo + { + public string Registry { get; set; } + public string Ordering { get; set; } + public int Supplement { get; set; } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCIDFont.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCIDFont.cs new file mode 100644 index 0000000000..c5415513a4 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCIDFont.cs @@ -0,0 +1,155 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal enum CIDFontSubtype + { + CIDFontType0, + CIDFontType2 + } + + internal class PdfCIDFont : PdfObject + { + private readonly CIDFontSubtype Subtype; + private readonly string BaseFont; + private readonly CIDSystemInfo CIDInfoObject; + private readonly int FontDescriptorObjectNumber; + + private readonly int? DW; // Default width + private readonly List W; // Width array + private readonly int[] DW2; // Default metrics for vertical writing (2 numbers) + private readonly List W2; // Vertical writing metrics + private readonly string CIDToGIDMap; // Can be string "Identity" or stream reference + + private HashSet Gids; + OpenTypeFont FontData; + + public PdfCIDFont(int objectNumber, OpenTypeFont fontData, HashSet gids, CIDFontSubtype subtype, CIDSystemInfo CIDSystemInfoObject, string CIDToGDI, int fontDescriptorObjectNumber, int version = 0) + : base(objectNumber, version) + { + Subtype = subtype; + BaseFont = string.Concat(fontData.FullName.Where(c => !char.IsWhiteSpace(c))); + CIDInfoObject = CIDSystemInfoObject; + FontDescriptorObjectNumber = fontDescriptorObjectNumber; + + FontData = fontData; + Gids = gids; + + DW = (int)Math.Round(1000.0d * 1000.0d / FontData.HeadTable.UnitsPerEm);//dw; + CIDToGIDMap = CIDToGDI; + } + + internal override string RenderDictionary() + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /{Subtype.ToString()}\n" + + $" /BaseFont /{BaseFont}\n" + + $" /CIDSystemInfo << /Registry ({CIDInfoObject.Registry}) /Ordering ({CIDInfoObject.Ordering}) /Supplement ({CIDInfoObject.Supplement}) >>\n" + + $" /FontDescriptor {FontDescriptorObjectNumber} 0 R"); + if (DW != null) + { + sb.AppendFormat($"\n /DW {DW}"); + } + if (Gids != null) + { + sb.AppendFormat($"\n /W [{BuildWidthsArray()}]"); + } + if (DW2 != null) + { + sb.AppendFormat($"\n /DW2 {DW2}"); + } + if (W2 != null) + { + var widthsStr = string.Join(" ", W2.Select(w => w.ToString()).ToArray()); + sb.AppendFormat($"\n /W2 [{widthsStr}]"); + } + if (Subtype == CIDFontSubtype.CIDFontType2) + { + if(string.IsNullOrEmpty( CIDToGIDMap )) + sb.AppendFormat($"\n /CIDToGIDMap {CIDToGIDMap}"); + else + sb.AppendFormat($"\n /CIDToGIDMap /Identity"); + } + sb.Append(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /{Subtype.ToString()}\n" + + $" /BaseFont /{BaseFont}\n" + + $" /CIDSystemInfo << /Registry ({CIDInfoObject.Registry}) /Ordering ({CIDInfoObject.Ordering}) /Supplement ({CIDInfoObject.Supplement}) >>\n" + + $" /FontDescriptor {FontDescriptorObjectNumber} 0 R"); + if (DW != null) + { + sb.AppendFormat($"\n /DW {DW}"); + } + if (Gids != null) + { + sb.AppendFormat($"\n /W [ {BuildWidthsArray()} ]"); + } + if (DW2 != null) + { + sb.AppendFormat($"\n /DW2 {DW2}"); + } + if (W2 != null) + { + var widthsStr = string.Join(" ", W2.Select(w => w.ToString()).ToArray()); + sb.AppendFormat($"\n /W2 [ {widthsStr} ]"); + } + if (Subtype == CIDFontSubtype.CIDFontType2) + { + if (string.IsNullOrEmpty(CIDToGIDMap)) + sb.AppendFormat($"\n /CIDToGIDMap {CIDToGIDMap}"); + else + sb.AppendFormat($"\n /CIDToGIDMap /Identity"); + } + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + } + + private string BuildWidthsArray() + { + var sortedGids = Gids.OrderBy(g => g).ToList(); + var sb = new StringBuilder(); + int i = 0; + while (i < sortedGids.Count) + { + ushort startGid = sortedGids[i]; + var widths = new List(); + + while (i < sortedGids.Count && sortedGids[i] == startGid + widths.Count) + { + int rawWidth = FontData.HmtxTable.GetAdvanceWidth(sortedGids[i]); + int scaledWidth = (int)Math.Round(1000.0d * rawWidth / FontData.HeadTable.UnitsPerEm); + widths.Add(scaledWidth); + i++; + } + sb.Append($"{startGid} ["); + sb.Append(string.Join(" ", widths.Select(w => w.ToString()).ToArray())); + sb.Append("] "); + } + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCidSet.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCidSet.cs new file mode 100644 index 0000000000..ce46bcf6a7 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfCidSet.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class PdfCidSet : PdfObject + { + byte[] CidSet; + + public PdfCidSet(int objectNumber, byte[] cidSet , int version = 0) : base(objectNumber, version) + { + CidSet = cidSet; + } + + internal override string RenderDictionary() + { + return $"<< /Length {CidSet.Length} >>\n" + $"stream\n|BINARY DATA|\nendstream"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + WriteAscii(bw, $"<< /Length {CidSet.Length} >>\nstream\n"); + bw.Write(CidSet); + WriteAscii(bw, "\nendstream"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFont.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFont.cs new file mode 100644 index 0000000000..54ece281b1 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFont.cs @@ -0,0 +1,130 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal enum PdfFontSubType + { + Type0, //Used for embedded fonts + Type1, //Used for built-in fonts + MMType1, + /*TODO*/Type3, //Custom front + /*TODO*/TrueType, //For embedding fonts + /*TODO*/CIDFontType0, // + /*TODO*/CIDFontType2, // + } + + internal enum PdfFontEncoding + { + None, + WinAnsiEncoding, + MacRomanEncoding, + } + + internal class PdfFont : PdfObject + { + private readonly string baseFont; + private readonly PdfFontSubType subType; + private readonly PdfFontEncoding encoding; + private readonly int firstChar; + private readonly int lastChar; + private readonly int widthObjectNumber; + private readonly int fontDescriptorObjectNumber; + + public PdfFont(int objectNumber, string fontName = "Helvetica", PdfFontSubType subType = PdfFontSubType.Type1, int firstChar = -1, int lastChar = -1, int widthObjectNumber = -1, int fontDescObjectNumner = -1, PdfFontEncoding encoding = PdfFontEncoding.WinAnsiEncoding) + : base(objectNumber, 0) + { + baseFont = fontName; + this.subType = subType; + this.encoding = encoding; + this.firstChar = firstChar; + this.lastChar = lastChar; + this.widthObjectNumber = widthObjectNumber; + fontDescriptorObjectNumber = fontDescObjectNumner; + } + + internal override string RenderDictionary() + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /{subType}\n" + + $" /BaseFont /{baseFont.Replace(" ", "")}"); + if (encoding == PdfFontEncoding.None) + { + sb.Append(" >>"); + return sb.ToString(); + } + else + { + sb.Append("\n"); + } + if (firstChar > -1) + { + sb.AppendFormat($" /FirstChar {firstChar}\n"); + } + if(lastChar > -1) + { + sb.AppendFormat($" /LastChar {lastChar}\n"); + } + if (widthObjectNumber > -1) + { + sb.AppendFormat($" /Widths {widthObjectNumber } 0 R\n"); + } + if (fontDescriptorObjectNumber > -1) + { + sb.AppendFormat($" /FontDescriptor {fontDescriptorObjectNumber} 0 R\n"); + } + sb.AppendFormat($" /Encoding /{encoding} >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /{subType}\n" + + $" /BaseFont /{baseFont.Replace(" ", "")}"); + if (encoding == PdfFontEncoding.None) + { + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + return; + } + else + { + sb.Append("\n"); + } + if (firstChar > -1) + { + sb.AppendFormat($" /FirstChar {firstChar}\n"); + } + if (lastChar > -1) + { + sb.AppendFormat($" /LastChar {lastChar}\n"); + } + if (widthObjectNumber > -1) + { + sb.AppendFormat($" /Widths {widthObjectNumber} 0 R\n"); + } + if (fontDescriptorObjectNumber > -1) + { + sb.AppendFormat($" /FontDescriptor {fontDescriptorObjectNumber} 0 R\n"); + } + sb.AppendFormat($" /Encoding /{encoding} >>"); + WriteAscii(bw, sb.ToString()); + return; + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontDescriptor.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontDescriptor.cs new file mode 100644 index 0000000000..a1833327b2 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontDescriptor.cs @@ -0,0 +1,110 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; +using System; +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + /// + /// Font descriptor flags + /// + [Flags] + internal enum FontDescriptorFlags + { + FixedPitch = 1, + Serif = 2, + Symbolic = 4, + Script = 8, + NonSymbolic = 32, + Italic = 64, + AllCap = 65536, + SmallCap = 131072, + ForceBold = 262144, + } + + internal class PdfFontDescriptor : PdfObject + { + private readonly string fontName; + private readonly int flags; + private readonly Rect fontBBox; + private readonly double italicAngle; + private readonly int ascent; + private readonly int descent; + private readonly double stemV; + private readonly int capheight; + private readonly int CidSetObjectNumber; + private readonly int FontFile2ObjectNumber; + + + public PdfFontDescriptor(int objectNumber, string fontName, int flags, Rect fontBBox, double italicAngle, int ascent, int descent, double stemV, int capHeight, int fontFile2ObjectNumber = -1, int cidSetObjectNumber = -1, int version = 0) + : base(objectNumber, version) + { + this.fontName = fontName; + this.flags = flags; + this.fontBBox = fontBBox; + this.italicAngle = italicAngle; + this.ascent = ascent; + this.descent = descent; + this.stemV = stemV; + capheight = capHeight; + CidSetObjectNumber = cidSetObjectNumber; + FontFile2ObjectNumber = fontFile2ObjectNumber; + } + + internal override string RenderDictionary() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /FontDescriptor\n" + + $" /FontName /{fontName.Replace(" ", "")}\n" + + $" /Flags {flags}\n" + + $" /FontBBox [{fontBBox.X} {fontBBox.Y} {fontBBox.Width} {fontBBox.Height}]\n" + + $" /Ascent {ascent}\n" + + $" /Descent {descent}\n" + + $" /CapHeight {capheight}\n" + + $" /ItalicAngle {(int)italicAngle}\n" + + $" /StemV {(int)stemV}"); + if (CidSetObjectNumber > 0) + { + sb.AppendFormat($"\n /CIDSet {CidSetObjectNumber} 0 R"); + } + if (FontFile2ObjectNumber > 0) + { + sb.AppendFormat($"\n /FontFile2 {FontFile2ObjectNumber} 0 R"); + } + sb.AppendFormat(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /FontDescriptor\n" + + $" /FontName /{fontName.Replace(" ", "")}\n" + + $" /Flags {flags}\n" + + $" /FontBBox [{fontBBox.X} {fontBBox.Y} {fontBBox.Width} {fontBBox.Height}]\n" + + $" /Ascent {ascent}\n" + + $" /Descent {descent}\n" + + $" /CapHeight {capheight}\n" + + $" /ItalicAngle {(int)italicAngle}\n" + + $" /StemV {(int)stemV}"); + if (FontFile2ObjectNumber > 0) + { + sb.AppendFormat($"\n /FontFile2 {FontFile2ObjectNumber} 0 R"); + } + sb.AppendFormat(" >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs new file mode 100644 index 0000000000..c3112d256e --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class PdfFontStream : PdfObject + { + private readonly OpenTypeFont FontData; + + public PdfFontStream(int objectNumber, OpenTypeFont fontData, int version = 0) : base(objectNumber, version) + { + FontData = fontData; + } + + internal override string RenderDictionary() + { + var fontBytes = FontData.Serialize(); + var fontData = Encoding.ASCII.GetString(fontBytes); + return $"<< /Length {fontBytes.Length} >>\n" + $"stream\n|BINARY DATA|\nendstream"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var fontBytes = FontData.Serialize(); + WriteAscii(bw, $"<< /Length {fontBytes.Length} >>\nstream\n"); + bw.Write(fontBytes); + WriteAscii(bw, "\nendstream"); + + using (var fs = new FileStream("c:\\epplustest\\pdf\\ExportedFont.ttf", FileMode.Create, FileAccess.Write)) + { + using (var bw2 = new BinaryWriter(fs, Encoding.ASCII)) + { + bw2.Write(fontBytes); + } + } + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontWidths.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontWidths.cs new file mode 100644 index 0000000000..1e515f51f1 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontWidths.cs @@ -0,0 +1,41 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class PdfFontWidths : PdfObject + { + internal readonly int[] widths; + + public PdfFontWidths(int objectNumber, List widths, int version = 0) + : base(objectNumber, version) + { + this.widths = widths.ToArray(); + } + + internal override string RenderDictionary() + { + var widthsStr = string.Join(" ", widths.Select(w => w.ToString()).ToArray()); + return $" [ {widthsStr} ]"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var widthsStr = string.Join(" ", widths.Select(w => w.ToString()).ToArray()); + WriteAscii(bw, $" [ {widthsStr} ]"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfToUnicodeCMap.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfToUnicodeCMap.cs new file mode 100644 index 0000000000..b317005fa5 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfToUnicodeCMap.cs @@ -0,0 +1,263 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class PdfToUnicodeCMap : PdfObject + { + private readonly Dictionary CharacterMappings; + private readonly int CodeSpaceMin; + private readonly int CodeSpaceMax; + private readonly int BytesPerCode; + + /// + /// Creates a ToUnicode CMap for mapping character codes to Unicode values + /// + /// PDF object number + /// Dictionary mapping character codes to Unicode strings (UTF-16BE hex format) + /// Minimum character code value (e.g., 0 for simple fonts) + /// Maximum character code value (e.g., 255 for simple fonts, 0xFFFF for CID fonts) + /// Number of bytes per character code (1 for simple fonts, 2 for CID fonts) + /// PDF object version + public PdfToUnicodeCMap(int objectNumber, Dictionary characterMappings, int codeSpaceMin = 0, int codeSpaceMax = 65535, int bytesPerCode = 2, int version = 0) : base(objectNumber, version) + { + CharacterMappings = characterMappings ?? new Dictionary(); + CodeSpaceMin = codeSpaceMin; + CodeSpaceMax = codeSpaceMax; + BytesPerCode = bytesPerCode; + } + + internal override string RenderDictionary() + { + var cmapContent = GenerateCMapContent(); + var length = Encoding.UTF8.GetByteCount(cmapContent); + var sb = new StringBuilder(); + sb.AppendLine(string.Format("<< /Length {0} >>", length)); + sb.AppendLine("stream"); + sb.Append(cmapContent); + sb.Append("\nendstream"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var cmapContent = GenerateCMapContent(); + var cmapBytes = Encoding.ASCII.GetBytes(cmapContent); + var sb = new StringBuilder(); + sb.AppendFormat(($"<< /Length {cmapBytes.Length} >>\n")); + sb.Append("stream\n"); + sb.Append(cmapContent); + sb.Append("\nendstream"); + WriteAscii(bw, sb.ToString()); + } + + private string GenerateCMapContent() + { + var sb = new StringBuilder(); + // CMap header + sb.Append("/CIDInit /ProcSet findresource begin\n"); + sb.Append("12 dict begin\n"); + sb.Append("begincmap\n"); + // CIDSystemInfo - required for ToUnicode CMaps + sb.Append("/CIDSystemInfo\n"); + sb.Append("<< /Registry (Adobe)\n"); + sb.Append(" /Ordering (UCS)\n"); + sb.Append(" /Supplement 0\n"); + sb.Append(">> def\n"); + // CMap name and type + sb.Append("/CMapName /Adobe-Identity-UCS def\n"); + sb.Append("/CMapType 2 def\n"); + // Define codespace range + sb.Append("1 begincodespacerange\n"); + sb.AppendFormat($"<{FormatCode(CodeSpaceMin)}> <{FormatCode(CodeSpaceMax)}>\n"); + sb.Append("endcodespacerange\n"); + // Generate character mappings + if (CharacterMappings.Count > 0) + { + GenerateCharacterMappings(sb); + } + // CMap footer + sb.Append("endcmap\n"); + sb.Append("CMapName currentdict /CMap defineresource pop\n"); + sb.Append("end\n"); + sb.Append("end"); + return sb.ToString(); + } + + private void GenerateCharacterMappings(StringBuilder sb) + { + // Group mappings into ranges where possible for efficiency + var sortedMappings = CharacterMappings.OrderBy(kvp => kvp.Key).ToList(); + var ranges = new List(); + var individualMappings = new List(); + // Try to identify consecutive ranges + for (int i = 0; i < sortedMappings.Count; i++) + { + var current = sortedMappings[i]; + // Try to parse as simple Unicode value for range detection + int unicodeValue; + if (TryParseSimpleUnicode(current.Value, out unicodeValue)) + { + int rangeStart = current.Key; + int rangeEnd = current.Key; + int unicodeStart = unicodeValue; + // Check if we can extend this into a range + while (i + 1 < sortedMappings.Count) + { + var next = sortedMappings[i + 1]; + int nextUnicode; + if (TryParseSimpleUnicode(next.Value, out nextUnicode) && + next.Key == rangeEnd + 1 && + nextUnicode == unicodeStart + (rangeEnd - rangeStart + 1)) + { + rangeEnd = next.Key; + i++; + } + else + { + break; + } + } + // If we found a range of 3 or more, use beginbfrange + if (rangeEnd - rangeStart >= 2) + { + ranges.Add(new CharacterRange(rangeStart, rangeEnd, unicodeStart)); + } + else + { + // Add individual mappings + for (int j = rangeStart; j <= rangeEnd; j++) + { + var mapping = sortedMappings.FirstOrDefault(m => m.Key == j); + individualMappings.Add(new CharacterMapping(j, mapping.Value)); + } + } + } + else + { + // Complex mapping (ligatures, etc.) - must be individual + individualMappings.Add(new CharacterMapping(current.Key, current.Value)); + } + } + // Output ranges + if (ranges.Count > 0) + { + sb.AppendFormat($"{ranges.Count} beginbfrange"); + foreach (var range in ranges) + { + sb.AppendFormat($"<{FormatCode(range.Start)}> <{FormatCode(range.End)}> <{FormatUnicode(range.UnicodeStart)}>\n"); + } + sb.Append("endbfrange\n"); + } + // Output individual character mappings + if (individualMappings.Count > 0) + { + // Process in batches of 100 (PDF best practice) + const int batchSize = 100; + for (int i = 0; i < individualMappings.Count; i += batchSize) + { + var batch = individualMappings.Skip(i).Take(batchSize).ToList(); + sb.AppendFormat($"{batch.Count} beginbfchar\n"); + foreach (var mapping in batch) + { + string hex = ((int)mapping.Unicode[0]).ToString("X4"); + sb.AppendFormat($"<{FormatCode(mapping.Code)}> <{hex}>\n"); + } + sb.Append("endbfchar\n"); + } + } + } + + private bool TryParseSimpleUnicode(string hexString, out int unicodeValue) + { + unicodeValue = 0; + // Check if it's a simple 4-digit hex Unicode value (e.g., "0041" for 'A') + if (hexString.Length == 4 && int.TryParse(hexString, System.Globalization.NumberStyles.HexNumber, null, out unicodeValue)) + { + return true; + } + return false; + } + + private string FormatCode(int code) + { + // Format character code as hex with appropriate byte length + if (BytesPerCode == 1) + { + return code.ToString("X2"); + } + else if (BytesPerCode == 2) + { + return code.ToString("X4"); + } + else if (BytesPerCode == 4) + { + return code.ToString("X8"); + } + else + { + // Default to 2 bytes + return code.ToString("X4"); + } + } + + private string FormatUnicode(int unicodeValue) + { + // Format Unicode value in UTF-16BE hex format + // For BMP characters (U+0000 to U+FFFF), use 4 hex digits + if (unicodeValue <= 0xFFFF) + { + return unicodeValue.ToString("X4"); + } + else + { + // For supplementary characters, convert to UTF-16 surrogate pair + unicodeValue -= 0x10000; + int highSurrogate = 0xD800 + (unicodeValue >> 10); + int lowSurrogate = 0xDC00 + (unicodeValue & 0x3FF); + return string.Format("{0:X4}{1:X4}", highSurrogate, lowSurrogate); + } + } + + // Helper classes to replace tuples + private class CharacterRange + { + public int Start { get; private set; } + public int End { get; private set; } + public int UnicodeStart { get; private set; } + + public CharacterRange(int start, int end, int unicodeStart) + { + Start = start; + End = end; + UnicodeStart = unicodeStart; + } + } + + private class CharacterMapping + { + public int Code { get; private set; } + public string Unicode { get; private set; } + + public CharacterMapping(int code, string unicode) + { + Code = code; + Unicode = unicode; + } + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfType0FontDict.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfType0FontDict.cs new file mode 100644 index 0000000000..010a673461 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfType0FontDict.cs @@ -0,0 +1,69 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Fonts +{ + internal class PdfType0FontDict : PdfObject + { + private readonly string BaseFont; + private readonly string Encoding; + private readonly int DescendantFontsObjectNumbers; + private readonly int ToUnicodeObjectNumber; + + public PdfType0FontDict(int objectNumber, string basefont, string encoding, int descendantFontsObjectNumbers, int toUnicodeObjectNumber = -1, int version = 0) + : base(objectNumber, version) + { + BaseFont = string.Concat(basefont.Where(c => !char.IsWhiteSpace(c))); + Encoding = encoding; + DescendantFontsObjectNumbers = descendantFontsObjectNumbers; + ToUnicodeObjectNumber = toUnicodeObjectNumber; + } + + internal override string RenderDictionary() + { + //var DescendantFonts = string.Join(" ", DescendantFontsObjectNumbers.Select(w => ($"{w} 0 R ").ToString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /Type0\n" + + $" /BaseFont /{BaseFont}\n" + + $" /Encoding /{Encoding}\n" + + $" /DescendantFonts [{DescendantFontsObjectNumbers} 0 R]"); + if (ToUnicodeObjectNumber > 0) + { + sb.AppendFormat($"\n /ToUnicode {ToUnicodeObjectNumber} 0 R"); + } + sb.Append(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + //var DescendantFonts = string.Join(" ", DescendantFontsObjectNumbers.Select(w => ($"{w} 0 R ").ToString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Font\n" + + $" /Subtype /Type0\n" + + $" /BaseFont /{BaseFont}\n" + + $" /Encoding /{Encoding}\n" + + $" /DescendantFonts [{DescendantFontsObjectNumbers} 0 R]"); + if (ToUnicodeObjectNumber > 0) + { + sb.AppendFormat($"\n /ToUnicode {ToUnicodeObjectNumber} 0 R"); + } + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfExponentialInterpolationFunction.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfExponentialInterpolationFunction.cs new file mode 100644 index 0000000000..41b2a99944 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfExponentialInterpolationFunction.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Functions +{ + internal class PdfExponentialInterpolationFunction : PdfFunction + { + internal double[] C0; + internal double[] C1; + internal double N; + + public PdfExponentialInterpolationFunction(int objectNumber, int version = 0) : base(objectNumber, version) { } + + internal override string RenderDictionary() + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + var c0Str = string.Join(" ", C0.Select(w => w.ToPdfString()).ToArray()); + var c1Str = string.Join(" ", C1.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /FunctionType 2\n" + + $" /Domain [ {domainStr} ]\n" + + $" /C0 [ {c0Str} ]\n" + + $" /C1 [ {c1Str} ]\n" + + $" /N {N.ToPdfString()} >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + var c0Str = string.Join(" ", C0.Select(w => w.ToPdfString()).ToArray()); + var c1Str = string.Join(" ", C1.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /FunctionType 2\n" + + $" /Domain [ {domainStr} ]\n" + + $" /C0 [ {c0Str} ]\n" + + $" /C1 [ {c1Str} ]\n" + + $" /N {N.ToPdfString()} >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfFunction.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfFunction.cs new file mode 100644 index 0000000000..5c393efc74 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfFunction.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.DocumentObjects.Functions +{ + internal abstract class PdfFunction : PdfObject + { + // Implemented Function type + // [ ] 0 Sampled function + // [X] 2 Exponential interpolation function + // [X] 3 Stitching function + // [ ] 4 PostScript calculator function + + internal double[] Domain; + internal double[] Range; + + public PdfFunction(int objectNumber, int version = 0) : base(objectNumber, version) { } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfStichingFunction.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfStichingFunction.cs new file mode 100644 index 0000000000..694caff8d6 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Functions/PdfStichingFunction.cs @@ -0,0 +1,59 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Functions +{ + internal class PdfStichingFunction : PdfFunction + { + internal List Functions = new List(); + internal double[] Bounds; + internal double[] Encode; + + public PdfStichingFunction(int objectNumber, int version = 0) : base(objectNumber, version) { } + + internal override string RenderDictionary() + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + var functionsStr = string.Join("\n", Functions.Select(w => w.RenderDictionary()).ToArray()); + var boundsStr = string.Join(" ", Bounds.Select(w => w.ToPdfString()).ToArray()); + var encodeStr = string.Join(" ", Encode.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /FunctionType 3\n" + + $" /Domain [ {domainStr} ]\n"); + sb.AppendFormat($" /Functions [ {functionsStr} ]\n"); + sb.AppendFormat($" /Bounds [ {boundsStr} ]\n" + + $" /Encode [ {encodeStr} ] >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + var functionsStr = string.Join("\n", Functions.Select(w => w.RenderDictionary()).ToArray()); + var boundsStr = string.Join(" ", Bounds.Select(w => w.ToPdfString()).ToArray()); + var encodeStr = string.Join(" ", Encode.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /FunctionType 3\n" + + $" /Domain [ {domainStr} ]\n"); + sb.AppendFormat($" /Functions [ {functionsStr} ]\n"); + sb.AppendFormat($" /Bounds [ {boundsStr} ]\n" + + $" /Encode [ {encodeStr} ] >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPattern.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPattern.cs new file mode 100644 index 0000000000..2706f64b02 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPattern.cs @@ -0,0 +1,19 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.DocumentObjects.Patterns +{ + internal abstract class PdfPattern : PdfObject + { + public PdfPattern(int objectNumber, int version = 0) : base(objectNumber, version) { } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternFill.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternFill.cs new file mode 100644 index 0000000000..959bf16971 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternFill.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.DocumentObjects.Patterns +{ + internal abstract class PdfPatternFill + { + public Color Background; + public Color Foreground; + + protected PdfPatternFill(Color foreground, Color background) + { + Foreground = foreground; + Background = background; + } + + public abstract string CreatePatternResource(); + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternMaskFill.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternMaskFill.cs new file mode 100644 index 0000000000..504598c138 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfPatternMaskFill.cs @@ -0,0 +1,89 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using System.Drawing; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Patterns +{ + /// + /// Renders a cell fill pattern from an 8x8 . + /// Replaces the former per-pattern PdfPatternFill subclasses: the geometry now + /// comes from a single verified mask catalog (taken from Excel's own PDF output) + /// instead of hand-coded rectangle coordinates. + /// + /// The whole 8x8 tile is filled with the Background color, then a rectangle is + /// drawn with the Foreground color for every foreground cell of the mask. + /// + /// The mask stores row 0 as the TOP row, while a PDF content stream has its + /// origin at the bottom-left with y increasing upward. The mask row r is + /// therefore emitted at PDF y = 7 - r (a mirror in y). Horizontally adjacent + /// foreground cells on the same row are merged into a single wider rectangle + /// to keep the content stream small. + /// + internal class PdfPatternMaskFill : PdfPatternFill + { + private readonly byte[,] _mask; + + public PdfPatternMaskFill(ExcelPatternMask pattern, Color foreground, Color background) + : base(foreground, background) + { + _mask = ExcelPatternMaskData.GetMask(pattern); + } + + public override string CreatePatternResource() + { + const int size = 8; + var sb = new StringBuilder(); + //Fill the whole tile with the background color. + sb.Append(Background.ToFillCommand()); + sb.Append("\n0 0 "); + sb.Append(size.ToString()); + sb.Append(" "); + sb.Append(size.ToString()); + sb.Append(" re\nf\n"); + // Draw foreground rectangles. mask value 0 == foreground. + sb.Append(Foreground.ToFillCommand()); + sb.Append("\n"); + for (int row = 0; row < size; row++) + { + int pdfY = (size - 1) - row; // mirror in y + int col = 0; + while (col < size) + { + if (_mask[row, col] == 0) + { + int start = col; + while (col < size && _mask[row, col] == 0) + { + col++; + } + int width = col - start; + sb.Append(start.ToString()); + sb.Append(" "); + sb.Append(pdfY.ToString()); + sb.Append(" "); + sb.Append(width.ToString()); + sb.Append(" 1 re\n"); + } + else + { + col++; + } + } + } + sb.Append("f"); + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfShadingPattern.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfShadingPattern.cs new file mode 100644 index 0000000000..8135ad90fe --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfShadingPattern.cs @@ -0,0 +1,62 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Patterns +{ + internal class PdfShadingPattern : PdfPattern + { + internal int shadingObjectNumber; + internal double[] Matrix; + //internal ExtGState dictionary //implement later + + public PdfShadingPattern(int objectNumber, int shadingObjectNumber, int version = 0) + : base(objectNumber, version) + { + this.shadingObjectNumber = shadingObjectNumber; + } + + internal override string RenderDictionary() + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Pattern\n" + + $" /PatternType 2\n" + + $" /Shading {shadingObjectNumber} 0 R"); + if (Matrix != null) + { + var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfStringF4()).ToArray()); + sb.AppendFormat($"\n /Matrix [ {matrixStr} ]"); + } + sb.Append(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Pattern\n" + + $" /PatternType 2\n" + + $" /Shading {shadingObjectNumber} 0 R"); + if (Matrix != null) + { + var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfStringF4()).ToArray()); + sb.AppendFormat($"\n /Matrix [ {matrixStr} ]"); + } + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfTilingPattern.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfTilingPattern.cs new file mode 100644 index 0000000000..5264b9aa3e --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Patterns/PdfTilingPattern.cs @@ -0,0 +1,100 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Patterns +{ + internal class PdfTilingPattern : PdfPattern + { + internal PdfPatternFill fill; + internal double[] BBox = [0d, 0d, 0d, 0d]; + internal double XStep = 0d; + internal double YStep = 0d; + internal double[] Matrix; + + public PdfTilingPattern(int objectNumber, PdfPatternFill patternFill, double[] BBox, double XStep, double YStep, int version = 0) : base(objectNumber, version) + { + fill = patternFill; + this.BBox = BBox; + this.XStep = XStep; + this.YStep = YStep; + } + + internal override string RenderDictionary() + { + var bboxStr = string.Join(" ", BBox.Select(x => x.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Pattern\n" + + $" /PatternType 1\n" + + $" /PaintType 1\n" + + $" /TilingType 1\n" + + $" /BBox [ {bboxStr} ]\n" + + $" /XStep {XStep.ToPdfString()}\n" + + $" /YStep {YStep.ToPdfString()}\n" + + $" /Resources << >>"); + if (Matrix != null) + { + var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfStringF4()).ToArray()); + sb.AppendFormat($"\n /Matrix [ {matrixStr} ]"); + } + if (fill != null) + { + var streamContent = fill.CreatePatternResource(); + var bytes = Encoding.ASCII.GetBytes(streamContent); + sb.AppendFormat($"\n /Length {bytes.Length}"); + sb.Append(" >>"); + sb.AppendFormat($"\nstream\n{streamContent}\nendstream"); + } + else + { + sb.Append(" >>"); + } + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var bboxStr = string.Join(" ", BBox.Select(x => x.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Pattern\n" + + $" /PatternType 1\n" + + $" /PaintType 1\n" + + $" /TilingType 1\n" + + $" /BBox [ {bboxStr} ]\n" + + $" /XStep {XStep.ToPdfString()}\n" + + $" /YStep {YStep.ToPdfString()}\n" + + $" /Resources << >>"); + if (Matrix != null) + { + var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfStringF4()).ToArray()); + sb.AppendFormat($"\n /Matrix [ {matrixStr} ]"); + } + if (fill != null) + { + var streamContent = fill.CreatePatternResource(); + var bytes = Encoding.ASCII.GetBytes(streamContent); + sb.AppendFormat($"\n /Length {bytes.Length}"); + sb.Append(" >>"); + sb.AppendFormat($"\nstream\n{streamContent}\nendstream"); + } + else + { + sb.Append(" >>"); + } + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs new file mode 100644 index 0000000000..489da65399 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs @@ -0,0 +1,434 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Layout; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfBorderRenderer + { + private readonly PdfCellBorderData Top; + private readonly PdfCellBorderData Bottom; + private readonly PdfCellBorderData Left; + private readonly PdfCellBorderData Right; + private readonly PdfCellBorderData DiagonalUp; + private readonly PdfCellBorderData DiagonalDown; + private readonly double X; + private readonly double Y; + private readonly string Name; + private readonly bool IsMerged; + private readonly MergedCellDrawInfo info; + private readonly double Width; + private readonly double Height; + + public PdfBorderRenderer(PdfCellBorderLayout cell) + { + IsMerged = cell.IsMerged; + info = cell.MergedCellInfo; + X = cell.LocalPosition.X; + Y = cell.LocalPosition.Y; + Width = cell.Size.X; + Height = cell.Size.Y; + Name = cell.Name; + Top = cell.BorderData.Top; + Bottom = cell.BorderData.Bottom; + Left = cell.BorderData.Left; + Right = cell.BorderData.Right; + DiagonalUp = cell.BorderData.DiagonalUp; + DiagonalDown = cell.BorderData.DiagonalDown; + //MergedDiagnoalWidth = DiagonalUp.MergedDiagonalWidth; + //MergedDiagnoalHeight = DiagonalDown.MergedDiagonalHeight; + } + + public void RenderBorder(PdfContentStream contentStream) + { + contentStream.AddCommand($"% Border Start: {Name}"); + contentStream.AddCommand("q"); + if (Top != null) RenderBorder(contentStream, Top); + if (Bottom != null) RenderBorder(contentStream, Bottom); + if (Left != null) RenderBorder(contentStream, Left); + if (Right != null) RenderBorder(contentStream, Right); + if (DiagonalUp != null) RenderBorder(contentStream, DiagonalUp); + if (DiagonalDown != null) RenderBorder(contentStream, DiagonalDown); + contentStream.AddCommand("Q"); + contentStream.AddCommand($"% Border End: {Name}"); + } + + private void RenderBorder(PdfContentStream contentStream, PdfCellBorderData border) + { + contentStream.AddCommand($"% Border Type Start: {border.LineType.ToString()}"); + double x1 = X, y1 = Y, x2 = X, y2 = Y; + switch (border.LineType) + { + case LineType.Top: + x1 = X; + y1 = Y + Height; + x2 = X + Width; + y2 = Y + Height; + break; + case LineType.Bottom: + x1 = X; + y1 = Y; + x2 = X + Width; + y2 = Y; + break; + case LineType.Left: + x1 = X; + y1 = Y; + x2 = X; + y2 = Y + Height; + break; + case LineType.Right: + x1 = X + Width; + y1 = Y; + x2 = X + Width; + y2 = Y + Height; + break; + case LineType.DiagonalUp: + if (IsMerged) + { + x1 = info.X; + y1 = info.Y - info.Height; + x2 = info.X + info.Width; + y2 = info.Y; + } + else + { + x1 = X; + y1 = Y; + x2 = X + Width; + y2 = Y + Height; + } + break; + case LineType.DiagonalDown: + if (IsMerged) + { + x1 = info.X; + y1 = info.Y; + x2 = info.X + info.Width; + y2 = info.Y - info.Height; + } + else + { + x1 = X; + y1 = Y + Height; + x2 = X + Width; + y2 = Y; + } + break; + } + if (border.IsHeading) + { + DrawBasicBorder(contentStream, border, PdfCellBorderData.OuterGridLine, PdfCellBorderData.NoDash); + contentStream.AddCommand($"{x1.ToPdfStringF4()} {y1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{x2.ToPdfStringF4()} {y2.ToPdfStringF4()} l"); + contentStream.AddCommand("S"); + contentStream.AddCommand($"% Border Type End: {border.LineType.ToString()}"); + return; + } + switch (border.BorderStyle) + { + case ExcelBorderStyle.None: + return; + case ExcelBorderStyle.Hair: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Hair, PdfCellBorderData.NoDash); + break; + case ExcelBorderStyle.Dotted: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Small, PdfCellBorderData.Dotted); + break; + case ExcelBorderStyle.DashDot: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Small, PdfCellBorderData.DashDot); + break; + case ExcelBorderStyle.Thin: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Thin, PdfCellBorderData.NoDash); + break; + case ExcelBorderStyle.DashDotDot: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Small, PdfCellBorderData.DashDotDot); + break; + case ExcelBorderStyle.Dashed: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Small, PdfCellBorderData.Dashed); + break; + case ExcelBorderStyle.MediumDashDotDot: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Medium, PdfCellBorderData.MediumDashDotDot); + break; + case ExcelBorderStyle.MediumDashed: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Medium, PdfCellBorderData.MediumDashed); + break; + case ExcelBorderStyle.MediumDashDot: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Medium, PdfCellBorderData.MediumDashDot); + break; + case ExcelBorderStyle.Thick: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Thick, PdfCellBorderData.NoDash); + break; + case ExcelBorderStyle.Medium: + DrawBasicBorder(contentStream, border, PdfCellBorderData.Medium, PdfCellBorderData.NoDash); + break; + case ExcelBorderStyle.SlantDashDot: + DrawSlantDashDotBorder(contentStream, border, x1, y1, x2, y2); + return; + case ExcelBorderStyle.Double: + DrawDoubleBorder(contentStream, border, x1, y1, x2, y2); + return; + } + contentStream.AddCommand($"{x1.ToPdfStringF4()} {y1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{x2.ToPdfStringF4()} {y2.ToPdfStringF4()} l"); + contentStream.AddCommand("S"); + contentStream.AddCommand($"% Border Type End: {border.LineType.ToString()}"); + } + + private void DrawBasicBorder(PdfContentStream contentStream, PdfCellBorderData border, double width, string dash) + { + contentStream.AddCommand(border.BorderColor.ToStrokeCommand()); + contentStream.AddCommand($"{width.ToPdfString()} w"); + contentStream.AddCommand(border.BorderStyle != ExcelBorderStyle.Dotted ? ( border.LineType == LineType.DiagonalUp || border.LineType == LineType.DiagonalDown ? "0 J" : "2 J" ) : "1 J"); + contentStream.AddCommand(dash); + } + + private void DrawDoubleBorder(PdfContentStream contentStream, PdfCellBorderData border, double x1, double y1, double x2, double y2) + { + var ix1 = x1; + var ix2 = x2; + var iy1 = y1; + var iy2 = y2; + var ox1 = x1; + var ox2 = x2; + var oy1 = y1; + var oy2 = y2; + + var DiagonalUpFactor = 0d; + var DiagonalDownFactor = 0d; + + if (border.LineType == LineType.Top) + { + ////Inner Line + //ix1 = x1; + //ix2 = x2; + //iy1 = y1 - (PdfCellBorderData.Hair / 0.65d); + //iy2 = y2 - (PdfCellBorderData.Hair / 0.65d); + //if (Left.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 0.7d; + //if (Right.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 0.7d; + //if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 4.87d; + //if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 4.87d; + + ix1 = x1; + ix2 = x2; + iy1 = y1 - (PdfCellBorderData.Hair / 0.65d); + iy2 = y2 - (PdfCellBorderData.Hair / 0.65d); + if (Left.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 0.7d; + if (Right.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 0.7d; + + // For a multi-column merged cell the diagonal endpoint sits at the far + // corner of the full merge, not at the right/left edge of this single + // cell column. Applying the indent here would create a gap at the wrong + // position along the top border, so suppress it. + bool multiColMerge = IsMerged && info.Width > Width + 0.5d; + if (!multiColMerge) + { + if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 4.87d; + if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 4.87d; + } + + //Outer Line + ox1 = x1; + ox2 = x2; + oy1 = y1 + (PdfCellBorderData.Hair / 0.65d); + oy2 = y2 + (PdfCellBorderData.Hair / 0.65d); + if (Left.BorderStyle != ExcelBorderStyle.None) ox1 = x1 - 0.7d; + if (Right.BorderStyle != ExcelBorderStyle.None) ox2 = x2 + 0.7d; + } + if (border.LineType == LineType.Bottom) + { + ix1 = x1; + ix2 = x2; + iy1 = y1 + (PdfCellBorderData.Hair / 0.65d); + iy2 = y2 + (PdfCellBorderData.Hair / 0.65d); + if (Left.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 0.7d; + if (Right.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 0.7d; + if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) ix1 = x1 + 4.87d; + if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) ix2 = x2 - 4.87d; + + ox1 = x1; + ox2 = x2; + oy1 = y1 - (PdfCellBorderData.Hair / 0.65d); + oy2 = y2 - (PdfCellBorderData.Hair / 0.65d); + if (Left.BorderStyle != ExcelBorderStyle.None) ox1 = x1 - 0.7d; + if (Right.BorderStyle != ExcelBorderStyle.None) ox2 = x2 + 0.7d; + } + else if (border.LineType == LineType.Left) + { + //DiagonalUpFactor = 0.5d; + //DiagonalDownFactor = 0.5d; + //ix1 = x1 + (PdfCellBorderData.Hair / 0.65d); + //ix2 = x2 + (PdfCellBorderData.Hair / 0.65d); + //iy1 = y1; + //iy2 = y2; + //if (Top.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d; + //if (Bottom.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d; + //if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d + DiagonalUpFactor; + //if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d - DiagonalDownFactor; + + DiagonalUpFactor = 0.5d; + DiagonalDownFactor = 0.5d; + ix1 = x1 + (PdfCellBorderData.Hair / 0.65d); + ix2 = x2 + (PdfCellBorderData.Hair / 0.65d); + iy1 = y1; + iy2 = y2; + if (Top.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d; + if (Bottom.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d; + + // For a multi-row merged cell the diagonal endpoint sits at the far + // corner of the full merge height, not at the bottom/top edge of this + // single row. Suppress the indent to avoid a gap at the wrong position. + bool multiRowMerge = IsMerged && info.Height > Height + 0.5d; + if (!multiRowMerge) + { + if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d + DiagonalUpFactor; + if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d - DiagonalDownFactor; + } + + ox1 = x1 - (PdfCellBorderData.Hair / 0.65d); + ox2 = x2 - (PdfCellBorderData.Hair / 0.65d); + oy1 = y1; + oy2 = y2; + if (Top.BorderStyle != ExcelBorderStyle.None) oy2 = y2 + 0.7d; + if (Bottom.BorderStyle != ExcelBorderStyle.None) oy1 = y1 - 0.7d; + } + else if (border.LineType == LineType.Right) + { + DiagonalUpFactor = 0.5d; + DiagonalDownFactor = 0.5d; + ix1 = x1 - (PdfCellBorderData.Hair / 0.65d); + ix2 = x2 - (PdfCellBorderData.Hair / 0.65d); + iy1 = y1; + iy2 = y2; + if (Top.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d; + if (Bottom.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d; + if (DiagonalUp.BorderStyle != ExcelBorderStyle.None) iy2 = y2 - 0.7d - DiagonalUpFactor; + if (DiagonalDown.BorderStyle != ExcelBorderStyle.None) iy1 = y1 + 0.7d + DiagonalDownFactor; + + ox1 = x1 + (PdfCellBorderData.Hair / 0.65d); + ox2 = x2 + (PdfCellBorderData.Hair / 0.65d); + oy1 = y1; + oy2 = y2; + if (Top.BorderStyle != ExcelBorderStyle.None) oy2 = y2 + 0.7d; + if (Bottom.BorderStyle != ExcelBorderStyle.None) oy1 = y1 - 0.7d; + } + else if (border.LineType == LineType.DiagonalUp) + { + ix1 = x1 + 0.6d; + ix2 = x2 - 4.87d; + iy1 = y1 + 0.98d; + iy2 = y2 - 0.765d; + ox1 = x1 + 4.87d; + ox2 = x2 - 0.6d; + oy1 = y1 + 0.765d; + oy2 = y2 - 0.98d; + } + else if (border.LineType == LineType.DiagonalDown) + { + ix1 = x1 + 0.6d; + ix2 = x2 - 4.87d; + iy1 = y1 - 0.98d; + iy2 = y2 + 0.765d; + ox1 = x1 + 4.87d; + ox2 = x2 - 0.6d; + oy1 = y1 - 0.765d; + oy2 = y2 + 0.98d; + } + contentStream.AddCommand(border.BorderColor.ToStrokeCommand()); + contentStream.AddCommand($"{PdfCellBorderData.Hair.ToPdfString()} w"); + contentStream.AddCommand(border.BorderStyle != ExcelBorderStyle.Dotted ? (border.LineType == LineType.DiagonalUp || border.LineType == LineType.DiagonalDown ? "0 J" : "2 J") : "1 J"); + contentStream.AddCommand(PdfCellBorderData.NoDash); + if ((border.LineType == LineType.DiagonalUp || border.LineType == LineType.DiagonalDown) && DiagonalUp.BorderStyle != ExcelBorderStyle.None && DiagonalDown.BorderStyle != ExcelBorderStyle.None) + { + + //break to method. + double dx = ix2 - ix1; + double dy = iy2 - iy1; + double length = System.Math.Sqrt(dx * dx + dy * dy); + + double ux = dx / length; + double uy = dy / length; + + double midX = (ix1 + ix2) / 2.0; + double midY = (iy1 + iy2) / 2.0; + + double leftDist = 0.25; + double rightDist = 2.15; + + double xA = midX - leftDist * ux; + double yA = midY - leftDist * uy; + double xB = midX + rightDist * ux; + double yB = midY + rightDist * uy; + + contentStream.AddCommand($"{ix1.ToPdfStringF4()} {iy1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{xA.ToPdfStringF4()} {yA.ToPdfStringF4()} l"); + contentStream.AddCommand($"{xB.ToPdfStringF4()} {yB.ToPdfStringF4()} m"); + contentStream.AddCommand($"{ix2.ToPdfStringF4()} {iy2.ToPdfStringF4()} l"); + + + dx = ox2 - ox1; + dy = oy2 - oy1; + length = System.Math.Sqrt(dx * dx + dy * dy); + + ux = dx / length; + uy = dy / length; + + midX = (ox1 + ox2) / 2.0; + midY = (oy1 + oy2) / 2.0; + + leftDist = 2.15; + rightDist = 0.25; + + xA = midX - leftDist * ux; + yA = midY - leftDist * uy; + xB = midX + rightDist * ux; + yB = midY + rightDist * uy; + + contentStream.AddCommand($"{ox1.ToPdfStringF4()} {oy1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{xA.ToPdfStringF4()} {yA.ToPdfStringF4()} l"); + contentStream.AddCommand($"{xB.ToPdfStringF4()} {yB.ToPdfStringF4()} m"); + contentStream.AddCommand($"{ox2.ToPdfStringF4()} {oy2.ToPdfStringF4()} l"); + } + else + { + contentStream.AddCommand($"{ix1.ToPdfStringF4()} {iy1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{ix2.ToPdfStringF4()} {iy2.ToPdfStringF4()} l"); + contentStream.AddCommand($"{ox1.ToPdfStringF4()} {oy1.ToPdfStringF4()} m"); + contentStream.AddCommand($"{ox2.ToPdfStringF4()} {oy2.ToPdfStringF4()} l"); + } + contentStream.AddCommand("S"); + } + private void DrawSlantDashDotBorder(PdfContentStream contentStream, PdfCellBorderData border, double x1, double y1, double x2, double y2) + { + contentStream.AddCommand(border.BorderColor.ToStrokeCommand()); + contentStream.AddCommand("Q"); + contentStream.AddCommand("q"); + contentStream.AddCommand($"{PdfCellBorderData.Small.ToPdfString()} w"); + contentStream.AddCommand(border.LineType == LineType.DiagonalUp || border.LineType == LineType.DiagonalDown ? "0 J" : "2 J"); + contentStream.AddCommand(PdfCellBorderData.DashDot); + contentStream.AddCommand($"1 0 0.6 1 0 0 cm"); + //calculate new x and y + var nx1 = x1 + y1 * 0.6d; + var tx1 = nx1 - x1; + var nx2 = x2 + y2 * 0.6d; + var tx2 = nx2 - x2; + contentStream.AddCommand($"{(x1 - tx1).ToPdfString()} {y1.ToPdfString()} m"); + contentStream.AddCommand($"{(x2 - tx2).ToPdfString()} {y2.ToPdfString()} l"); + contentStream.AddCommand("S"); + contentStream.AddCommand("Q"); + contentStream.AddCommand("q"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfCatalog.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfCatalog.cs new file mode 100644 index 0000000000..cbb0f96f61 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfCatalog.cs @@ -0,0 +1,39 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfCatalog : PdfObject + { + private readonly int pagesObjectNumber; + + public PdfCatalog(int objectNumber, int pagesObjectNumber, int version = 0) + : base(objectNumber, version) + { + this.pagesObjectNumber = pagesObjectNumber; + } + + internal override string RenderDictionary() + { + return $"<< /Type /Catalog\n" + + $" /Pages {pagesObjectNumber} 0 R >>"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + WriteAscii(bw, $"<< /Type /Catalog\n" + + $" /Pages {pagesObjectNumber} 0 R >>"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs new file mode 100644 index 0000000000..7039d470ad --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs @@ -0,0 +1,405 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Enums; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfContentStream : PdfObject + { + private readonly List commands = new List(); + + public PdfContentStream(int objectNumber, string command = null, int version = 0) + : base(objectNumber, version) + { + if (!string.IsNullOrEmpty(command)) + { + commands.Add(command); + } + } + + public void AddCommand(string command) + { + commands.Add(command); + } + + public void AddCellLayout(PdfCellLayout cell, string label) + { + if (cell.CellFillData.GradientFillData != null && cell.CellFillData.PatternStyle != ExcelFillStyle.Solid) + { + commands.Add($"% Pattern Start: {cell.Name}"); + commands.Add("q"); + commands.Add("/Pattern cs"); + commands.Add($"/{label} scn"); + commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); + commands.Add("f"); + commands.Add("Q"); + commands.Add($"% Pattern End: {cell.Name}"); + } + else if (cell.CellFillData.BackgroundColor != Color.Empty && cell.CellFillData.PatternStyle == ExcelFillStyle.Solid) + { + commands.Add($"% Solid Fill Start: {cell.Name}"); + commands.Add("q"); + commands.Add($"{GridLine.HalfWidth.ToPdfString()} w"); + commands.Add(cell.CellFillData.BackgroundColor.ToFillCommand()); + commands.Add(cell.CellFillData.enhanceGridLine ? Color.Black.ToStrokeCommand() : cell.CellFillData.BackgroundColor.ToStrokeCommand()); + commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); + commands.Add("B"); + commands.Add("Q"); + commands.Add($"% Solid Fill End: {cell.Name}"); + } + else if (cell.CellFillData.PatternStyle != ExcelFillStyle.None) + { + commands.Add($"% Pattern Start: {cell.Name}"); + // Draw the solid cell background only when one is set. The pattern + // tile already fills itself with its own background color, so the + // pattern must be rendered regardless of whether the cell has a + // separate background fill (it may be Color.Empty). + if (cell.CellFillData.BackgroundColor != Color.Empty) + { + commands.Add("q"); + commands.Add($"{GridLine.HalfWidth.ToPdfString()} w"); + commands.Add(cell.CellFillData.BackgroundColor.ToFillCommand()); + commands.Add(cell.CellFillData.BackgroundColor.ToStrokeCommand()); + commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); + commands.Add("B"); + commands.Add("Q"); + } + + commands.Add("q"); + commands.Add("/Pattern cs"); + commands.Add($"/{label} scn"); + commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); + commands.Add("f"); + commands.Add("Q"); + commands.Add($"% Pattern End: {cell.Name}"); + } + } + + public void AddBorderLayout(PdfCellBorderLayout cell) + { + var borderRenderer = new PdfBorderRenderer(cell); + borderRenderer.RenderBorder(this); + } + + public void AddText(PdfCellContentLayout cell, Vector2 position, double textRotation, PdfDictionaries dictionaries, PdfPageSettings pageSettings) + { + double advanceY = 0d; + double line0Width = cell.TextLines.Count > 0 ? cell.TextLines[0].Width : 0d; + double rotation = textRotation * System.Math.PI / 180.0; + for (int k = 0; k < cell.TextLines.Count; k++) + { + var line = cell.TextLines[k]; + double lineOffsetX = 0d; + switch (cell.CellAlignmentData.HorizontalAlignment) + { + case ExcelHorizontalAlignment.Right: + lineOffsetX = line0Width - line.Width; + break; + case ExcelHorizontalAlignment.Center: + lineOffsetX = (line0Width - line.Width) / 2d; + break; + } + double advanceX = 0; + for (int i = 0; i < line.LineFragments.Count; i++) + { + var textFormat = line.LineFragments[i]; + // find which ShapedText owns this fragment + int shapedTextIndex = 0; + int shapedTextCharStart = 0; + for (int s = 0; s < cell.ShapedTexts.Count; s++) + { + int shapedTextCharCount = cell.ShapedTexts[s].ShapedText.Glyphs.Sum(g => g.CharCount); + if (textFormat.StartFullTextIdx < shapedTextCharStart + shapedTextCharCount) + { + shapedTextIndex = s; + break; + } + shapedTextCharStart += shapedTextCharCount; + } + var shapedText = cell.ShapedTexts[shapedTextIndex]; + + // find the starting glyph within that ShapedText using StartRtIdx + int glyphStart = 0; + int charOffsetInShapedText = textFormat.StartFullTextIdx - shapedTextCharStart; + int rtCharCount = 0; + for (int g = 0; g < shapedText.ShapedText.Glyphs.Length; g++) + { + if (rtCharCount >= charOffsetInShapedText) + { + glyphStart = g; + break; + } + rtCharCount += shapedText.ShapedText.Glyphs[g].CharCount; + } + var originalFragment = ((TextFragment)textFormat.OriginalTextFragment); + while (glyphStart < shapedText.ShapedText.Glyphs.Length && shapedText.ShapedText.Glyphs[glyphStart].GlyphId == 0) + { + shapedTextIndex++; + if (shapedTextIndex >= cell.ShapedTexts.Count) + { + break; // temp safety + } + shapedText = cell.ShapedTexts[shapedTextIndex]; + glyphStart = 0; + } + + var richInfo = originalFragment.RichTextOptions; + var textLength = shapedText.ShapedText.GetWidthInPoints((float)richInfo.Size); + var color = richInfo.FontColor; + var fontResource = dictionaries.GetFont(richInfo.Family, richInfo.SubFamily); + double size = richInfo.Size; + double scale = textFormat.OriginalTextFragment.RichTextOptions.Size / fontResource.fontData.HeadTable.UnitsPerEm; + Matrix3x3 textMatrix = new Matrix3x3(System.Math.Cos(rotation), System.Math.Sin(rotation), -System.Math.Sin(rotation), System.Math.Cos(rotation), position.X + lineOffsetX, position.Y + advanceY); + commands.Add("BT"); + textMatrix = textMatrix * Matrix3x3.Translation(advanceX, 0); + if (richInfo.SuperScript) + { + var supOffX = fontResource.fontData.Os2Table.ySuperscriptXOffset * scale; + var supOffY = fontResource.fontData.Os2Table.ySuperscriptYOffset * scale; + var supSizeY = fontResource.fontData.Os2Table.ySuperscriptYSize * scale; + textMatrix = textMatrix * Matrix3x3.Translation(supOffX, supOffY); + size = supSizeY; + } + else if (richInfo.SubScript) + { + var supOffX = fontResource.fontData.Os2Table.ySubscriptXOffset * scale; + var supOffY = fontResource.fontData.Os2Table.ySubscriptYOffset * scale; + var supSizeY = fontResource.fontData.Os2Table.ySubscriptYSize * scale; + textMatrix = textMatrix * Matrix3x3.Translation(supOffX, supOffY); + size = supSizeY; + } + if (richInfo.UnderlineType != 12) + { + var underlinePos = fontResource.fontData.PostTable.underlinePosition * scale; + var underlineWidth = fontResource.fontData.PostTable.underlineThickness * scale; + var start = textMatrix.Transform(new Vector2(0, underlinePos)); + var end = textMatrix.Transform(new Vector2(textLength, underlinePos)); + commands.Add($"{underlineWidth.ToPdfString()} w"); + commands.Add($"{start.X.ToPdfString()} {start.Y.ToPdfString()} m"); + commands.Add($"{end.X.ToPdfString()} {end.Y.ToPdfString()} l"); + commands.Add($"S"); + } + if (richInfo.StrikeType > 1) + { + var strikePos = fontResource.fontData.Os2Table.yStrikeoutPosition * scale; + var strikeWidth = fontResource.fontData.Os2Table.yStrikeoutSize * scale; + var start = textMatrix.Transform(new Vector2(0, strikePos)); + var end = textMatrix.Transform(new Vector2(textLength, strikePos)); + commands.Add($"{strikeWidth.ToPdfString()} w"); + commands.Add($"{start.X.ToPdfString()} {start.Y.ToPdfString()} m"); + commands.Add($"{end.X.ToPdfString()} {end.Y.ToPdfString()} l"); + commands.Add($"S"); + } + commands.Add(color.ToFillCommand()); + commands.Add($"{textMatrix.A.ToPdfStringF4()} {textMatrix.B.ToPdfStringF4()} {textMatrix.C.ToPdfStringF4()} {textMatrix.D.ToPdfStringF4()} {textMatrix.E.ToPdfStringF4()} {textMatrix.F.ToPdfStringF4()} Tm"); + + // FIX: Always use fontIdMap to determine the initial font. + // FontId=0 does NOT always mean "primary font" — when the text starts + // with a fallback character (e.g. emoji), FontId=0 IS the fallback font. + // The fontIdMap correctly maps FontId → PDF font label in all cases. + byte currentFontId = shapedText.ShapedText.Glyphs.Length > 0 ? shapedText.ShapedText.Glyphs[0].FontId : (byte)0; + string currentFontLabel = shapedText.FontIdMap.ContainsKey(currentFontId) + ? shapedText.FontIdMap[currentFontId] + : fontResource.Label; + commands.Add($"/{currentFontLabel} {size.ToPdfString()} Tf"); + int fragmentCharCount = textFormat.Text.Length; + int charsRendered = 0; + var sb = new StringBuilder(); + sb.Append("["); + for (int j = glyphStart; j < shapedText.ShapedText.Glyphs.Length; j++) + { + if (charsRendered >= fragmentCharCount) + break; + var glyph = shapedText.ShapedText.Glyphs[j]; + if (glyph.FontId != currentFontId) + { + // Close TJ array, switch font, open new TJ array + sb.Append("] TJ\n"); + sb.Append($"/{shapedText.FontIdMap[glyph.FontId]} {size.ToPdfString()} Tf\n"); + sb.Append("["); + currentFontId = glyph.FontId; + } + sb.Append($"<{glyph.GlyphId:X4}>"); + int kerning = glyph.XAdvance - glyph.BaseAdvance; + if (kerning != 0) + { + double adjustment = -(kerning * 1000.0 / 1000); + sb.Append($" {adjustment.ToPdfStringF0()}"); + } + if (j < shapedText.ShapedText.Glyphs.Length - 1) + { + sb.Append(" "); + } + charsRendered += glyph.CharCount; + } + advanceX += textLength; + commands.Add(sb.ToString() + "] TJ"); + commands.Add("ET"); + } + advanceY -= (line.LargestAscent + line.LargestDescent); + } + } + + public void AddCellContentLayout(PdfCellContentLayout cell, PdfDictionaries dictionaries, PdfPageSettings pageSettings) + { + commands.Add($"% Content Start: {cell.Name}"); + commands.Add("q"); + if (cell.Clip) AddClipping(cell); + AddText(cell, cell.LocalPosition, cell.CellAlignmentData.TextRotation, dictionaries, pageSettings); + commands.Add("Q"); + commands.Add($"% Content End: {cell.Name}"); + } + + private void AddClipping(PdfCellContentLayout cell) + { + commands.Add($"{cell.Clipping.X.ToPdfString()} {cell.Clipping.Y.ToPdfString()} {cell.Clipping.Width.ToPdfString()} {cell.Clipping.Height.ToPdfString()} re W n"); + } + + public void AddInnerGridLines(Transform pageLayout) + { + if (pageLayout is not PdfPageLayout pl) return; + if (pl.isCommentsPage) return; + + commands.Add($"% Gridlines Start"); + commands.Add("q"); + commands.Add($"{GridLine.Width.ToPdfString()} w"); + commands.Add(Color.Black.ToFillCommand()); + foreach (var line in pl.GridLines) + { + string w, h; + if (line.X1 == line.X2) + { + w = GridLine.Width.ToPdfStringF4(); + h = System.Math.Abs(line.Y2 - line.Y1).ToPdfStringF4(); + } + else + { + w = System.Math.Abs(line.X2 - line.X1).ToPdfStringF4(); + h = GridLine.Width.ToPdfStringF4(); + } + var x = Math.Min(line.X1, line.X2); + var y = Math.Min(line.Y1, line.Y2); + commands.Add($"{x.ToPdfStringF4()} {y.ToPdfStringF4()} {w} {h} re"); + } + commands.Add("f"); + commands.Add("Q"); + commands.Add($"% Gridlines End"); + } + + public void AddPrintTitleGridLines(Transform pageLayout) + { + if (pageLayout is not PdfPageLayout pl) return; + if (pl.isCommentsPage) return; + + commands.Add($"% Print Title Gridlines Start"); + commands.Add("q"); + commands.Add($"{GridLine.Width.ToPdfString()} w"); + commands.Add(Color.Black.ToFillCommand()); + foreach (var line in pl.PrintTitleGridLines) + { + string w, h; + if (line.X1 == line.X2) + { + w = GridLine.Width.ToPdfStringF4(); + h = System.Math.Abs(line.Y2 - line.Y1).ToPdfStringF4(); + } + else + { + w = System.Math.Abs(line.X2 - line.X1).ToPdfStringF4(); + h = GridLine.Width.ToPdfStringF4(); + } + var x = Math.Min(line.X1, line.X2); + var y = Math.Min(line.Y1, line.Y2); + commands.Add($"{x.ToPdfStringF4()} {y.ToPdfStringF4()} {w} {h} re"); + } + commands.Add("f"); + commands.Add("Q"); + commands.Add($"% Print Title Gridlines End"); + } + + public void AddOuterGridBorder(Transform pageLayout) + { + if (pageLayout is not PdfPageLayout pl) return; + if (pl.isCommentsPage) return; + + commands.Add($"% Gridlines Border Start"); + commands.Add("q"); + commands.Add("1.0 w"); + commands.Add("2 J"); + commands.Add("[] 0 d"); + commands.Add(Color.Black.ToStrokeCommand()); + foreach (var line in pl.BorderLines) + { + commands.Add($"{line.X1.ToPdfStringF4()} {line.Y1.ToPdfStringF4()} m"); + commands.Add($"{line.X2.ToPdfStringF4()} {line.Y2.ToPdfStringF4()} l"); + } + commands.Add("S"); + commands.Add("Q"); + commands.Add($"% Gridlines Border End"); + } + + public void AddMarginClipping(PdfPageLayout pageLayout) + { + if (pageLayout is not PdfPageLayout pl) return; + if (pageLayout.isCommentsPage) return; + commands.Add($"% Margin Clip Start"); + // Derive the tight bounding box directly from BorderLines. + // pageLayout is created with all-zero dimensions so ContentTop/Bottom/Left/Height + // cannot be used here — they are always 0. + double top = double.MinValue; + double bottom = double.MaxValue; + double left = double.MaxValue; + double right = double.MinValue; + foreach (var line in pl.BorderLines) + { + top = System.Math.Max(top, System.Math.Max(line.Y1, line.Y2)); + bottom = System.Math.Min(bottom, System.Math.Min(line.Y1, line.Y2)); + left = System.Math.Min(left, System.Math.Min(line.X1, line.X2)); + right = System.Math.Max(right, System.Math.Max(line.X1, line.X2)); + } + var pad = GridLine.Width * 4; + var x = left + pl.HeadingWidth + pl.PrintTitleWidth - pad; + var y = bottom - pad; + var width = (right - left - pl.HeadingWidth - pl.PrintTitleWidth) + pad * 2; + var height = (top - pl.HeadingHeight - pl.PrintTitleHeight - bottom) + pad * 2; + commands.Add($"{x.ToPdfString()} {y.ToPdfString()} {width.ToPdfString()} {height.ToPdfString()} re W n"); + } + + internal override string RenderDictionary() + { + var content = string.Join("\n", commands.ToArray()) + "\n"; + var bytes = Encoding.ASCII.GetBytes(content); + return $"<< /Length {bytes.Length} >>\n" + $"stream\n{content}endstream"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var content = string.Join("\n", commands.ToArray()) + "\n"; + var bytes = Encoding.ASCII.GetBytes(content); + WriteAscii(bw, $"<< /Length {bytes.Length} >>\nstream\n{content}\nendstream"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfCrossRefTable.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfCrossRefTable.cs new file mode 100644 index 0000000000..57d7ddd8c2 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfCrossRefTable.cs @@ -0,0 +1,54 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfCrossRefTable + { + private readonly List positions = new List(); + internal long StartPosition { get; private set; } + + internal void AddPosition(long position) + { + positions.Add(position); + } + + internal string WriteString(int bodyCount) + { + StringBuilder sb = new StringBuilder(); + sb.Append("xref\n"); + sb.AppendFormat($"0 {bodyCount + 1}\n"); + sb.Append("0000000000 65535 f \n"); + foreach (long pos in positions) + { + sb.AppendFormat(pos.ToString("D10") + " 00000 n \n"); + } + return sb.ToString(); + } + + internal void Write(BinaryWriter bw, long startPosition, int bodyCount) + { + StartPosition = startPosition; + bw.Write(Encoding.ASCII.GetBytes("xref\n")); + bw.Write(Encoding.ASCII.GetBytes($"0 {bodyCount + 1}\n")); + bw.Write(Encoding.ASCII.GetBytes("0000000000 65535 f \n")); + foreach (long pos in positions) + { + bw.Write(Encoding.ASCII.GetBytes(pos.ToString("D10") + " 00000 n \n")); + } + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfInfoObject.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfInfoObject.cs new file mode 100644 index 0000000000..4937c84fb2 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfInfoObject.cs @@ -0,0 +1,66 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfInfoObject : PdfObject + { + public string Title; + + public PdfInfoObject(int objectNumber, string Title, int version = 0) : base(objectNumber, version) + { + this.Title = Title; + } + + internal override string RenderDictionary() + { + DateTime now = DateTime.Now; + TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(now); + string sign = offset < TimeSpan.Zero ? "-" : "+"; + offset = offset.Duration(); + string pdfDate = string.Format("D:{0:yyyyMMddHHmmss}{1}{2:00}'{3:00}'", now, sign, offset.Hours, offset.Minutes); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Title ({Title})\n" + + $" /Author (EPPlus)\n" + + $" /Subject (EPPlus PDF Export)\n" + + $" /Keywords (EPPlus, EPPlus Software)" + + $" /Creator (EPPlus Software)\n" + + $" /Producer (EPPlus Software PDF Exporter)\n" + + $" /CreationDate ({pdfDate})\n" + + $" /ModDate ({pdfDate})\n" + + $" /Trapped /False >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + DateTime now = DateTime.Now; + TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(now); + string sign = offset < TimeSpan.Zero ? "-" : "+"; + offset = offset.Duration(); + string pdfDate = string.Format("D:{0:yyyyMMddHHmmss}{1}{2:00}'{3:00}'", now, sign, offset.Hours, offset.Minutes); + WriteAscii(bw, $"<< /Title ({Title})\n" + + $" /Author (EPPlus)\n" + + $" /Subject (EPPlus PDF Export)\n" + + $" /Keywords (EPPlus, EPPlus Software)\n" + + $" /Creator (EPPlus Software)\n" + + $" /Producer (EPPlus Software PDF Exporter)\n" + + $" /CreationDate ({pdfDate})\n" + + $" /ModDate ({pdfDate})\n" + + $" /Trapped /False >>"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfObject.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfObject.cs new file mode 100644 index 0000000000..b8213d3c05 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfObject.cs @@ -0,0 +1,55 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal abstract class PdfObject + { + internal int objectNumber; + internal int version; + + public PdfObject(int objectNumber, int version = 0) + { + this.objectNumber = objectNumber; + this.version = version; + } + + public virtual string ToPdfString() + { + var sb = new StringBuilder(); + sb.AppendFormat("{0} {1} obj\n", objectNumber, version); + sb.Append(RenderDictionary()); + sb.Append("\nendobj\n"); + return sb.ToString(); + } + + public virtual void ToPdfBytes(BinaryWriter bw) + { + var sb = new StringBuilder(); + WriteAscii(bw, $"{objectNumber} {version} obj\n"); + RenderDictionary(bw); + WriteAscii(bw, $"\nendobj\n"); + } + + protected static void WriteAscii(BinaryWriter bw, string s) + { + bw.Write(Encoding.ASCII.GetBytes(s)); + } + + internal abstract string RenderDictionary(); + + internal abstract void RenderDictionary(BinaryWriter bw); + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfPage.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfPage.cs new file mode 100644 index 0000000000..a7632d8c2f --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfPage.cs @@ -0,0 +1,95 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings.PdfPageSizes; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfPage : PdfObject + { + private readonly int parentObjectNumber; + internal readonly List contentObjectNumbers; + PdfDictionaries dictionaries; + internal PdfPageSize Size; + + public PdfPage(int objectNumber, int parentObjectNumber, List contentObjectNumbers, PdfPageSize size, PdfDictionaries dictionaries, int version = 0) + : base(objectNumber, version) + { + this.parentObjectNumber = parentObjectNumber; + this.contentObjectNumbers = contentObjectNumbers; + this.dictionaries = dictionaries; + Size = size; + } + + internal override string RenderDictionary() + { + var fontEntries = dictionaries.Fonts.Select(f => $"/{f.Value.Label} {f.Value.fontObjectNumber} 0 R").ToArray(); + var fonts = string.Join(" ", fontEntries); + var patternEntries = dictionaries.Patterns.Select(p => $"/{p.Value.Label} {p.Value.objectNumber} 0 R").ToArray(); + var patterns = string.Join(" ", patternEntries); + var shadingEntries = dictionaries.Shadings.Select(s => $"/{s.Value.Label} {s.Value.objectNumber} 0 R").ToArray(); + var shadings = string.Join(" ", shadingEntries); + var contentEntries = contentObjectNumbers.Select(con => $"{con} 0 R").ToArray(); + StringBuilder sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Page\n" + + $" /Parent {parentObjectNumber} 0 R\n"); + bool hasFont = !string.IsNullOrEmpty(fonts); + bool hasPattern = !string.IsNullOrEmpty(patterns); + bool hasShading = !string.IsNullOrEmpty(shadings); + if (hasFont || hasPattern || hasShading) + { + sb.AppendFormat($" /Resources <<\n"); + if (hasFont ) sb.AppendFormat($" /Font << {fonts} >>\n"); + if (hasPattern) sb.AppendFormat($" /Pattern << {patterns} >>\n"); + if (hasShading) sb.AppendFormat($" /Shading << {shadings} >>\n"); + sb.AppendFormat($" >>\n"); + } + sb.AppendFormat($" /MediaBox [ 0 0 {Size.WidthPu.ToPdfString()} {Size.HeightPu.ToPdfString()} ]\n" + + $" /Contents [ {string.Join(" ", contentEntries)} ] >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var fontEntries = dictionaries.Fonts.Select(f => $"/{f.Value.Label} {f.Value.fontObjectNumber} 0 R").ToArray(); + var fonts = string.Join(" ", fontEntries); + var patternEntries = dictionaries.Patterns.Select(p => $"/{p.Value.Label} {p.Value.objectNumber} 0 R").ToArray(); + var patterns = string.Join(" ", patternEntries); + var shadingEntries = dictionaries.Shadings.Select(s => $"/{s.Value.Label} {s.Value.objectNumber} 0 R").ToArray(); + var shadings = string.Join(" ", shadingEntries); + var contentEntries = contentObjectNumbers.Select(con => $"{con} 0 R").ToArray(); + StringBuilder sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Page\n" + + $" /Parent {parentObjectNumber} 0 R\n"); + bool hasFont = !string.IsNullOrEmpty(fonts); + bool hasPattern = !string.IsNullOrEmpty(patterns); + bool hasShading = !string.IsNullOrEmpty(shadings); + if (hasFont || hasPattern || hasShading) + { + sb.AppendFormat($" /Resources <<\n"); + if (hasFont ) sb.AppendFormat($" /Font << {fonts} >>\n"); + if (hasPattern) sb.AppendFormat($" /Pattern << {patterns} >>\n"); + if (hasShading) sb.AppendFormat($" /Shading << {shadings} >>\n"); + sb.AppendFormat($" >>\n"); + } + sb.AppendFormat($" /MediaBox [ 0 0 {Size.WidthPu.ToPdfString()} {Size.HeightPu.ToPdfString()} ]\n" + + $" /Contents [ {string.Join(" ", contentEntries)} ] >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfPages.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfPages.cs new file mode 100644 index 0000000000..a2684d13f4 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfPages.cs @@ -0,0 +1,47 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal class PdfPages : PdfObject + { + internal readonly List pageObjectNumbers; + + public PdfPages(int objectNumber, List pageObjectNumbers, int version = 0) + : base(objectNumber, version) + { + this.pageObjectNumbers = pageObjectNumbers.ToList(); + } + + internal override string RenderDictionary() + { + var kids = string.Join(" ", pageObjectNumbers.Select(n => $"{n} 0 R").ToArray()); + return $"<< /Type /Pages\n" + + $" /Kids [ {kids} ]\n" + + $" /Count {pageObjectNumbers.Count} >>"; + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var kids = string.Join(" ", pageObjectNumbers.Select(n => $"{n} 0 R").ToArray()); + StringBuilder sb = new StringBuilder(); + WriteAscii(bw, $"<< /Type /Pages\n" + + $" /Kids [ {kids} ]\n" + + $" /Count {pageObjectNumbers.Count} >>"); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfTrailer.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfTrailer.cs new file mode 100644 index 0000000000..80245bbf71 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfTrailer.cs @@ -0,0 +1,44 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects +{ + internal static class PdfTrailer + { + internal static string WriteString(int bodyCount, int catalogObjectNumber, int infoObjectNumber, long crossRefStartPosition) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("trailer\n"); + sb.AppendFormat($"<< /Size {bodyCount + 1}\n" + + $" /Root {catalogObjectNumber} 0 R\n" + + $" /Info {infoObjectNumber} 0 R >>\n"); + sb.AppendFormat("startxref\n"); + sb.AppendFormat($"{crossRefStartPosition}\n"); + sb.AppendFormat("%%EOF\n"); + return sb.ToString(); + } + + internal static void Write(BinaryWriter bw, int bodyCount, int catalogObjectNumber, int infoObjectNumber, long crossRefStartPosition) + { + bw.Write(Encoding.ASCII.GetBytes($"trailer\n" + + $"<< /Size {bodyCount + 1}\n" + + $" /Root {catalogObjectNumber} 0 R\n" + + $" /Info {infoObjectNumber} 0 R >>\n" + + $"startxref\n" + + $"{crossRefStartPosition}\n" + + $"%%EOF\n")); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfAxialShading.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfAxialShading.cs new file mode 100644 index 0000000000..e4fdab6884 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfAxialShading.cs @@ -0,0 +1,126 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; +using System.Linq; +using System.Text; +using System.IO; +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.DocumentObjects.Functions; +using EPPlus.Export.Pdf.Helpers; + +namespace EPPlus.Export.Pdf.DocumentObjects.Shadings +{ + internal class PdfAxialShading : PdfShading + { + internal double[] Coords; + internal double[] Domain; + internal double[] Matrix; + internal PdfFunction Function; + internal bool[] Extend = null; + + public PdfAxialShading(int objectNumber, PdfCellGradientFillData GradientFillData, int version = 0) + : base(objectNumber, version) + { + //Fun test later for diagonal gradients. Diagonal gradients are set to 45 degrees, but in excel they go from corner to corner. To replicate this we could create out 45 in a square that we then scale to fill the dell. + ColorSpace = DeviceColorSpace.DeviceRGB; + Coords = [0, 0, 1, 0]; + if (!GradientFillData.Color3.Equals(Color.Empty)) + { + var func = new PdfStichingFunction(0); + func.Domain = [0d, 1d]; + func.Bounds = [0.5d]; + func.Encode = [0d, 1d, 1d, 0d]; + var f1 = new PdfExponentialInterpolationFunction(0); + f1.C0 = [GradientFillData.Color1.GetR(), GradientFillData.Color1.GetG(), GradientFillData.Color1.GetB()]; + f1.C1 = [GradientFillData.Color3.GetR(), GradientFillData.Color3.GetG(), GradientFillData.Color3.GetB()]; + f1.Domain = [0, 1]; + f1.N = 1; + func.Functions.Add(f1); + var f2 = new PdfExponentialInterpolationFunction(0); + f2.C0 = [GradientFillData.Color2.GetR(), GradientFillData.Color2.GetG(), GradientFillData.Color2.GetB()]; + f2.C1 = [GradientFillData.Color3.GetR(), GradientFillData.Color3.GetG(), GradientFillData.Color3.GetB()]; + f2.Domain = [0, 1]; + f2.N = 1; + func.Functions.Add(f2); + Function = func; + } + else + { + var func = new PdfExponentialInterpolationFunction(0); + func.C0 = [GradientFillData.Color1.GetR(), GradientFillData.Color1.GetG(), GradientFillData.Color1.GetB()]; + func.C1 = [GradientFillData.Color2.GetR(), GradientFillData.Color2.GetG(), GradientFillData.Color2.GetB()]; + func.Domain = [0, 1]; + func.N = 1; + Function = func; + } + //Matrix = GradientFillData.matrix; + Extend = [true, true]; + } + + internal override string RenderDictionary() + { + var coordsStr = string.Join(" ", Coords.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 2\n" + + $" /ColorSpace /{ColorSpace.ToString()}\n" + + $" /Coords [ {coordsStr} ]\n"); + sb.AppendFormat($" /Function {Function.RenderDictionary()}"); + if (Domain != null) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + sb.AppendFormat($"\n /Domain [ {domainStr} ]"); + } + //if (Matrix != null) + //{ + // var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfString()).ToArray()); + // sb.AppendFormat($"\n /matrix [ {matrixStr} ]"); + //} + if (Extend != null) + { + var extendStr = string.Join(" ", Extend.Select(w => w.ToString().ToLower()).ToArray()); + sb.AppendFormat($"\n /Extend [ {extendStr} ]"); + } + sb.Append(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var coordsStr = string.Join(" ", Coords.Select(w => w.ToPdfString()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 2\n" + + $" /ColorSpace /{ColorSpace.ToString()}\n" + + $" /Coords [ {coordsStr} ]\n"); + sb.AppendFormat($" /Function {Function.RenderDictionary()}"); + if (Domain != null) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + sb.AppendFormat($"\n /Domain [ {domainStr} ]"); + } + //if (Matrix != null) + //{ + // var matrixStr = string.Join(" ", Matrix.Select(w => w.ToPdfString()).ToArray()); + // sb.AppendFormat($"\n /matrix [ {matrixStr} ]"); + //} + if (Extend != null) + { + var extendStr = string.Join(" ", Extend.Select(w => w.ToString().ToLower()).ToArray()); + sb.AppendFormat($"\n /Extend [ {extendStr} ]"); + } + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfRadialShading.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfRadialShading.cs new file mode 100644 index 0000000000..6760f686b0 --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfRadialShading.cs @@ -0,0 +1,92 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.DocumentObjects.Functions; +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Layout; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Shadings +{ + internal class PdfRadialShading : PdfShading + { + internal double[] Coords; + internal double[] Domain; + internal List Functions = new List(); + internal bool[] Extend = null; + + public PdfRadialShading(int objectNumber, PdfCellGradientFillData GradientFillData, int version = 0) + : base(objectNumber, version) + { + ColorSpace = DeviceColorSpace.DeviceRGB; + Coords = [0, 0, 1, 0]; + var func = new PdfExponentialInterpolationFunction(0); + func.C0 = [GradientFillData.Color1.GetR(), GradientFillData.Color1.GetG(), GradientFillData.Color1.GetB()]; + func.C1 = [GradientFillData.Color2.GetR(), GradientFillData.Color2.GetG(), GradientFillData.Color2.GetB()]; + func.Domain = [0, 1]; + func.N = 1; + Functions.Add(func); + Extend = [true, true]; + } + + internal override string RenderDictionary() + { + var coordsStr = string.Join(" ", Coords.Select(w => w.ToPdfString()).ToArray()); + var functionsStr = string.Join("\n", Functions.Select(w => w.RenderDictionary()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 3\n" + + $" /ColorSpace /{ColorSpace.ToString()}\n" + + $" /Coords [ {coordsStr} ]\n"); + sb.AppendFormat($" /Function {functionsStr}"); + if (Domain != null) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + sb.AppendFormat($"\n /Domain [ {domainStr} ]"); + } + if (Extend != null) + { + var extendStr = string.Join(" ", Extend.Select(w => w.ToString().ToLower()).ToArray()); + sb.AppendFormat($"\n /Extend [ {extendStr} ]"); + } + sb.Append(" >>"); + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var coordsStr = string.Join(" ", Coords.Select(w => w.ToPdfString()).ToArray()); + var functionsStr = string.Join("\n", Functions.Select(w => w.RenderDictionary()).ToArray()); + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 3\n" + + $" /ColorSpace /{ColorSpace.ToString()}\n" + + $" /Coords [ {coordsStr} ]\n"); + sb.AppendFormat($" /Function {functionsStr}"); + if (Domain != null) + { + var domainStr = string.Join(" ", Domain.Select(w => w.ToPdfString()).ToArray()); + sb.AppendFormat($"\n /Domain [ {domainStr} ]"); + } + if (Extend != null) + { + var extendStr = string.Join(" ", Extend.Select(w => w.ToString().ToLower()).ToArray()); + sb.AppendFormat($"\n /Extend [ {extendStr} ]"); + } + sb.Append(" >>"); + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfShading.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfShading.cs new file mode 100644 index 0000000000..ba3754247a --- /dev/null +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Shadings/PdfShading.cs @@ -0,0 +1,86 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; +using System.IO; +using System.Text; + +namespace EPPlus.Export.Pdf.DocumentObjects.Shadings +{ + internal enum DeviceColorSpace + { + DeviceGray, + DeviceRGB, + DeviceCMYK, + } + + internal class PdfShading : PdfObject + { + // Implemented Function type + // [ ] 1 Function-based shading + // [X] 2 Axial shading + // [ ] 3 Radial shading + // [ ] 4 Free-form Gouraud-shaded triangle mesh + // [ ] 5 Lattice-form Gouraud-shaded triangle mesh + // [ ] 6 Coons patch mesh + // [ ] 7 Tensor-product patch mesh + + internal DeviceColorSpace ColorSpace; + internal double[] Background = null; + internal Rect BBox = null; + internal bool? AntiAlias = null; + + public PdfShading(int objectNumber, int version = 0) : base(objectNumber, version) { } + + internal override string RenderDictionary() + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 0\n" + + $" /ColorSpace {ColorSpace.ToString()}"); + if (Background != null) + { + //add background + } + if (BBox != null) + { + //add bbox + } + if (AntiAlias != null) + { + sb.AppendFormat($"\n /AntiAlias {AntiAlias.ToString()}"); + } + return sb.ToString(); + } + + internal override void RenderDictionary(BinaryWriter bw) + { + var sb = new StringBuilder(); + sb.AppendFormat($"<< /Type /Shading\n" + + $" /ShadingType 0\n" + + $" /ColorSpace {ColorSpace.ToString()}"); + if (Background != null) + { + //add background + } + if (BBox != null) + { + //add bbox + } + if (AntiAlias != null) + { + sb.AppendFormat($"\n /AntiAlias {AntiAlias.ToString()}"); + } + WriteAscii(bw, sb.ToString()); + } + } +} diff --git a/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.csproj b/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.csproj new file mode 100644 index 0000000000..1aa441393c --- /dev/null +++ b/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.csproj @@ -0,0 +1,78 @@ + + + + net8.0;net9.0;netstandard2.1;netstandard2.0;net462 + disable + disable + true + EPPlus.Export.Pdf.snk + latest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.snk b/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.snk new file mode 100644 index 0000000000..dfb13404d3 Binary files /dev/null and b/src/EPPlus.Export.Pdf/EPPlus.Export.Pdf.snk differ diff --git a/src/EPPlus.Export.Pdf/Enums/EPPlusEnums.cs b/src/EPPlus.Export.Pdf/Enums/EPPlusEnums.cs new file mode 100644 index 0000000000..16fd7987a6 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Enums/EPPlusEnums.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Export.Pdf.Enums +{ + /// + /// Horizontal text alignment + /// + public enum ExcelHorizontalAlignment + { + /// + /// General aligned + /// + General, + /// + /// Left aligned + /// + Left, + /// + /// Center aligned + /// + Center, + /// + /// The horizontal alignment is centered across multiple cells + /// + CenterContinuous, + /// + /// Right aligned + /// + Right, + /// + /// The value of the cell should be filled across the entire width of the cell. + /// + Fill, + /// + /// Each word in each line of text inside the cell is evenly distributed across the width of the cell + /// + Distributed, + /// + /// The horizontal alignment is justified to the Left and Right for each row. + /// + Justify + } + /// + /// Vertical text alignment + /// + public enum ExcelVerticalAlignment + { + /// + /// Top aligned + /// + Top, + /// + /// Center aligned + /// + Center, + /// + /// Bottom aligned + /// + Bottom, + /// + /// Distributed. Each line of text inside the cell is evenly distributed across the height of the cell + /// + Distributed, + /// + /// Justify. Each line of text inside the cell is evenly distributed across the height of the cell + /// + Justify + } + /// + /// The reading order + /// + public enum ExcelReadingOrder + { + /// + /// Reading order is determined by the first non-whitespace character + /// + ContextDependent = 0, + /// + /// Left to Right + /// + LeftToRight = 1, + /// + /// Right to Left + /// + RightToLeft = 2 + } + /// + /// Fill pattern + /// + public enum ExcelFillStyle + { + /// + /// No fill + /// + None, + /// + /// A solid fill + /// + Solid, + /// + /// Dark gray + /// Excel name: 75% Gray + /// + DarkGray, + /// + /// Medium gray + /// Excel name: 50% Gray + /// + MediumGray, + /// + /// Light gray + /// Excel name: 25% Gray + /// + LightGray, + /// + /// Grayscale of 0.125, 1/8 + /// Excel name: 12.5% Gray + /// + Gray125, + /// + /// Grayscale of 0.0625, 1/16 + /// Excel name: 6.25% Gray + /// + Gray0625, + /// + /// Dark vertical + /// Excel name: Vertical Stripe + /// + DarkVertical, + /// + /// Dark horizontal + /// Excel name: Horizontal Stripe + /// + DarkHorizontal, + /// + /// Dark down + /// Excel name: Reverse Diagonal Stripe + /// + DarkDown, + /// + /// Dark up + /// Excel name: Diagonal Stripe + /// + DarkUp, + /// + /// Dark grid + /// Excel name: Diagonal Crosshatch + /// + DarkGrid, + /// + /// Dark trellis + /// Excel name: Thick Diagonal Crosshatch + /// + DarkTrellis, + /// + /// Light vertical + /// Excel name: Thin Vertical Stripe + /// + LightVertical, + /// + /// Light horizontal + /// Excel name: Thin Horizontal Stripe + /// + LightHorizontal, + /// + /// Light down + /// Excel name: Thin Reverse Diagonal Stripe + /// + LightDown, + /// + /// Light up + /// Excel name: Thin Diagonal Stripe + /// + LightUp, + /// + /// Light grid + /// Excel name: Thin Horizontal Crosshatch + /// + LightGrid, + /// + /// Light trellis + /// Excel name: Thin Diagonal Crosshatch + /// + LightTrellis + } + /// + /// BulletType of gradient fill + /// + public enum ExcelFillGradientType + { + /// + /// No gradient fill. + /// + None, + /// + /// Linear gradient type. Linear gradient type means that the transition from one color to the next is along a line. + /// + Linear, + /// + /// Path gradient type. Path gradient type means the that the transition from one color to the next is a rectangle, defined by coordinates. + /// + Path + } + /// + /// Border line style + /// + public enum ExcelBorderStyle + { + /// + /// No border style + /// + None, + /// + /// Hairline + /// + Hair, + /// + /// Dotted + /// + Dotted, + /// + /// Dash Dot + /// + DashDot, + /// + /// Thin single line + /// + Thin, + /// + /// Dash Dot Dot + /// + DashDotDot, + /// + /// Dashed + /// + Dashed, + /// + /// Dash Dot Dot, medium thickness + /// + MediumDashDotDot, + /// + /// Dashed, medium thickness + /// + MediumDashed, + /// + /// Dash Dot, medium thickness + /// + MediumDashDot, + /// + /// Single line, Thick + /// + Thick, + /// + /// Single line, medium thickness + /// + Medium, + /// + /// Double line + /// + Double, + /// + /// Slanted Dash Dot + /// + SlantDashDot + } +} diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs new file mode 100644 index 0000000000..d9d1834d56 --- /dev/null +++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs @@ -0,0 +1,291 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.DocumentObjects; +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Graphics; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.Pdf +{ + /// + /// Class for exporting to PDF format. + /// + internal class ExcelPdf + { + private PdfPageSettings _pageSettings; + private PdfDictionaries _dictionaries; + private List _document = new List(); + private string _debugString; + + internal static string Header + { + get + { + return "%PDF-1.7\n"; + } + } + + //Get the label to use for pattern. + private string GetPatternLabel(PdfCellLayout layout) + { + bool isPattern = (layout.CellFillData.PatternStyle != ExcelFillStyle.Solid && layout.CellFillData.PatternStyle != ExcelFillStyle.None) || layout.CellFillData.GradientFillData != null; + if (isPattern) + { + var patternName = layout.CellFillData.id; + if (patternName != null && _dictionaries.Patterns.ContainsKey(patternName)) + { + return _dictionaries.Patterns[patternName].Label; + } + } + return null; + } + + //Add Fonts //Need to update this method a bit. We should check for all default fonts and not only courier new? Also need to check if we are allowed to embedd the font. + private void AddFontData() + { + if (_pageSettings.EmbeddFonts) + { + foreach (var font in _dictionaries.Fonts) + { + //font.Value.CreateGidsAndCharMaps(); + var cidSet = font.Value.GetCidSet(_document.Count + 1); + if (cidSet != null) _document.Add(cidSet); + _document.Add(font.Value.GetEmbeddedFontStreamObject(_document.Count + 1)); + _document.Add(font.Value.GetFontDescriptorObject(_document.Count + 1)); + _document.Add(font.Value.GetCIDFontObject(_document.Count + 1)); + _document.Add(font.Value.GetUnicodeCmapObject(_document.Count + 1)); + _document.Add(font.Value.GetType0FontDictObject(_document.Count + 1)); + font.Value.GetFontObject(_document.Count); + } + } + else + { + foreach (var font in _dictionaries.Fonts) + { + _document.Add(font.Value.GetFontDescriptorObject(_document.Count + 1)); + _document.Add(font.Value.GetWidthsObject(_document.Count + 1)); + _document.Add(font.Value.GetFontObject(_document.Count + 1)); + } + } + } + + //Add Patterns + private void AddPatternData() + { + foreach (var pattern in _dictionaries.Patterns) + { + _document.Add(pattern.Value.GetPatternObject(_document.Count + 1)); + } + } + + //Add Shadings and accompanying pattern + private void AddShadingsData() + { + foreach (var shading in _dictionaries.Shadings) + { + _document.Add(shading.Value.GetShadingObject(_document.Count + 1)); + _document.Add(shading.Value.GetShadingPatternObject(_document.Count + 1, _document.Count)); + int label = _dictionaries.Patterns.Last().Value.labelNumber + 1; + var pr = new PdfPatternResource(label, shading.Value.CellFillData); + pr.objectNumber = _document.Count; + _dictionaries.Patterns.Add(shading.Value.CellFillData.id, pr); + } + } + + //Create Page + private PdfPage AddPage(int pagesObjectNumber, List contentObjectNumbers, PdfPageSettings settings) + { + var page = new PdfPage(_document.Count + 1, pagesObjectNumber, contentObjectNumbers, settings.PageSize, _dictionaries); + _document.Add(page); + return page; + } + + //Create Pages + private PdfPages AddPages() + { + var pages = new PdfPages(_document.Count + 1, new List { }); + _document.Add(pages); + return pages; + } + + //Create Catalog + private PdfCatalog AddCatalog(int pagesObjectNumber) + { + var catalog = new PdfCatalog(_document.Count + 1, pagesObjectNumber); + _document.Add(catalog); + return catalog; + } + + //Create Content + private void AddContent(Transform pageLayout, PdfPage page) + { + var cells = pageLayout.ChildObjects.Where(t => + (t is PdfCellLayout || t is PdfCellContentLayout || t is PdfCellBorderLayout) && + !(t is PdfCellLayout cc && (cc.IsHeading || cc.IsPrintTitle)) && + !(t is PdfCellContentLayout ccl && (ccl.IsHeaderFooter || ccl.IsHeading || ccl.IsPrintTitle)) && + !(t is PdfCellBorderLayout cbl && cbl.IsPrintTitle)).GroupBy(t => t.Name); + + + var headerFooterLayouts = pageLayout.ChildObjects.OfType().Where(t => t.IsHeaderFooter); + var headingLayouts = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout cl && cl.IsHeading) || (t is PdfCellContentLayout ccl && ccl.IsHeading)); + var printTitleLayouts = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout pl && pl.IsPrintTitle) || (t is PdfCellContentLayout pcl && pcl.IsPrintTitle) || (t is PdfCellBorderLayout pbl && pbl.IsPrintTitle)); + var contentStream = new PdfContentStream(_document.Count + 1); + contentStream.AddCommand($"% {pageLayout.Name} start"); + //Add clipping rectangle around page content. + contentStream.AddCommand("q"); + contentStream.AddMarginClipping((PdfPageLayout)pageLayout); + if (_pageSettings.ShowGridLines) + { + contentStream.AddInnerGridLines(pageLayout); + } + foreach (var cell in cells) + { + foreach (var cellPart in cell) + { + contentStream.AddCommand($"% CELL : {cellPart.Name}"); + switch (cellPart) + { + case PdfCellLayout layout: + contentStream.AddCellLayout(layout, GetPatternLabel(layout)); + break; + case PdfCellContentLayout contentLayout: + contentStream.AddCellContentLayout(contentLayout, _dictionaries, _pageSettings); + break; + case PdfCellBorderLayout borderLayout: + contentStream.AddBorderLayout(borderLayout); + break; + } + } + } + //Close the clipping rectangle. + contentStream.AddCommand("Q"); + contentStream.AddCommand($"% Margin Clip End"); + // Heading cells render outside the clip — no merged-cell content can obscure them. + foreach (var heading in headingLayouts) + { + contentStream.AddCommand($"% HEADING : {heading.Name}"); + switch (heading) + { + case PdfCellLayout layout: + contentStream.AddCellLayout(layout, GetPatternLabel(layout)); break; + case PdfCellContentLayout contentLayout: + contentStream.AddCellContentLayout(contentLayout, _dictionaries, _pageSettings); break; + case PdfCellBorderLayout borderLayout: + contentStream.AddBorderLayout(borderLayout); break; + } + } + if (_pageSettings.ShowGridLines || _pageSettings.ShowHeadings) + { + contentStream.AddOuterGridBorder(pageLayout); + contentStream.AddPrintTitleGridLines(pageLayout); + } + //Add header and footer. + foreach (var hf in headerFooterLayouts) + { + contentStream.AddCellContentLayout(hf, _dictionaries, _pageSettings); + } + foreach (var titleCell in printTitleLayouts) + { + contentStream.AddCommand($"% PRINT TITLE : {titleCell.Name}"); + switch (titleCell) + { + case PdfCellLayout layout: + contentStream.AddCellLayout(layout, GetPatternLabel(layout)); break; + case PdfCellContentLayout contentLayout: + contentStream.AddCellContentLayout(contentLayout, _dictionaries, _pageSettings); break; + case PdfCellBorderLayout borderLayout: + contentStream.AddBorderLayout(borderLayout); break; + } + } + _document.Add(contentStream); + page.contentObjectNumbers.Add(contentStream.objectNumber); + contentStream.AddCommand($"% {pageLayout.Name} end"); + } + + //Add Info + private PdfInfoObject AddInfoObject(string workBookName = "") + { + var info = new PdfInfoObject(_document.Count + 1, workBookName); + _document.Add(info); + return info; + } + + internal void CreatePdf(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Transform layout, string fileName) + { + _pageSettings = pageSettings; + _dictionaries = dictionaries; + var catalog = AddCatalog(2); + //Create Pages + var pagesLayout = layout.ChildObjects[0]; + var pages = AddPages(); + //Create Fonts + AddFontData(); + //Create Patterns + AddPatternData(); + //Create Shadings + AddShadingsData(); + //Create Page and Content + for (int i = 0; i < layout.ChildObjects.Count; i++) + { + var pageLayout = layout.ChildObjects[i]; + var page = AddPage(2, new List(), _pageSettings); + AddContent(pageLayout, page); + pages.pageObjectNumbers.Add(page.objectNumber); + } + var info = AddInfoObject(); + string debugString = ""; + //write to pdf + PdfCrossRefTable crossRefTable = new PdfCrossRefTable(); + //start wring pdf binary + using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + { + using (var bw = new BinaryWriter(fs, Encoding.ASCII)) + { + //Write header + bw.Write(Encoding.ASCII.GetBytes(Header)); + debugString += Header; + //Write body + foreach (var pdfobj in _document) + { + crossRefTable.AddPosition(fs.Position); + pdfobj.ToPdfBytes(bw); + debugString += pdfobj.ToPdfString(); + } + //Write CrossReference + crossRefTable.Write(bw, fs.Position, _document.Count); + debugString += crossRefTable.WriteString(_document.Count); + // Write trailer + PdfTrailer.Write(bw, _document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); + debugString += PdfTrailer.WriteString(_document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); + } + } + //Write pdf as txt for debug. + if (_pageSettings.Debug && _pageSettings.PrintAsText) + { + using (var fs = new FileStream(fileName + ".txt", FileMode.Create, FileAccess.Write)) + { + using (var wr = new StreamWriter(fs)) + { + wr.Write(debugString); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/Helpers/PdfColor.cs b/src/EPPlus.Export.Pdf/Helpers/PdfColor.cs new file mode 100644 index 0000000000..2378b042c4 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Helpers/PdfColor.cs @@ -0,0 +1,132 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; +using System.Drawing; +using System.Globalization; + +namespace EPPlus.Export.Pdf.Helpers +{ + internal static class PdfColor + { + /// + /// Returns the red component of the color as a nomralized value. + /// + /// The color to extract the component + /// Normalized value of the color component. + public static float GetR(this Color c) => c.R / 255f; + + /// + /// Returns the green component of the color as a nomralized value. + /// + /// The color to extract the component + /// Normalized value of the color component. + public static float GetG(this Color c) => c.G / 255f; + + /// + /// Returns the blue component of the color as a nomralized value. + /// + /// The color to extract the component + /// Normalized value of the color component. + public static float GetB(this Color c) => c.B / 255f; + + /// + /// Returns the alpha component of the color as a nomralized value. + /// + /// The color to extract the component + /// Normalized value of the color component. + public static float GetA(this Color c) => c.A / 255f; + + /// + /// Convert a hex string representing a color into a color. + /// + /// String with corlor in hex code. + /// Valid inputs that sets color to Color.Empty: + /// "#0" + /// "0" + /// "" + /// null + /// + /// System.Drawing.Color object. + /// Throws exception of string is in invalid format. + public static Color SetColorFromHex(string hex) + { + if (string.IsNullOrEmpty(hex) || hex == "0" || hex == "#0") + { + return Color.Empty; + + } + hex = hex.Trim().TrimStart('#'); + int R=0, G=0, B=0, A=0; + if (hex.Length == 3) + { + R = Convert.ToByte(new string(hex[0], 2), 16); + G = Convert.ToByte(new string(hex[1], 2), 16); + B = Convert.ToByte(new string(hex[2], 2), 16); + + } + else if (hex.Length == 4) + { + A = Convert.ToByte(new string(hex[0], 2), 16); + R = Convert.ToByte(new string(hex[1], 2), 16); + G = Convert.ToByte(new string(hex[2], 2), 16); + B = Convert.ToByte(new string(hex[3], 2), 16); + } + else if (hex.Length == 6) + { + R = Convert.ToByte(hex.Substring(0, 2), 16); + G = Convert.ToByte(hex.Substring(2, 2), 16); + B = Convert.ToByte(hex.Substring(4, 2), 16); + } + else if (hex.Length == 8) + { + A = Convert.ToByte(hex.Substring(0, 2), 16); + R = Convert.ToByte(hex.Substring(2, 2), 16); + G = Convert.ToByte(hex.Substring(4, 2), 16); + B = Convert.ToByte(hex.Substring(6, 2), 16); + } + else + { + throw new FormatException("Invalid hex color format."); + } + return Color.FromArgb(A, R, G, B); + } + + /// + /// Returns a string for pdf command for stroke. + /// + /// The color to use for stroke. + /// The command string for a stroke color + public static string ToStrokeCommand(this Color c) => $"{c.GetR().ToString("F", CultureInfo.InvariantCulture)} {c.GetG().ToString("F", CultureInfo.InvariantCulture)} {c.GetB().ToString("F", CultureInfo.InvariantCulture)} RG"; + + /// + /// Returns a string for pdf command for fill. + /// + /// The color to use for fill. + /// The command string for a fill color + public static string ToFillCommand(this Color c) => $"{c.GetR().ToString("F", CultureInfo.InvariantCulture)} {c.GetG().ToString("F", CultureInfo.InvariantCulture)} {c.GetB().ToString("F", CultureInfo.InvariantCulture)} rg"; + + /// + /// Get the color represented in Hex as a string. + /// + /// The color which to return the hex value as a string. + /// String represeting the hex value of the color. + public static string ToHexString(this Color c) + { + int r = (int)(c.R); + int g = (int)(c.G); + int b = (int)(c.B); + int a = (int)(c.A); + return $"#{r:X2}{g:X2}{b:X2}{a:X2}"; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Helpers/PdfString.cs b/src/EPPlus.Export.Pdf/Helpers/PdfString.cs new file mode 100644 index 0000000000..d26aea06f6 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Helpers/PdfString.cs @@ -0,0 +1,49 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Globalization; + +namespace EPPlus.Export.Pdf.Helpers +{ + internal static class PdfString + { + /// + /// Returns the value formated for use in pdf document. + /// + /// Value to turn into a string. + /// The value repsented as a string. + internal static string ToPdfString(this double val) + { + return val.ToString(CultureInfo.InvariantCulture); + } + + /// + /// Returns the value formated for use in pdf document. + /// + /// Value to turn into a string. + /// The value repsented as a string with 4 decimals. + internal static string ToPdfStringF4(this double val) + { + return val.ToString("F4", CultureInfo.InvariantCulture); + } + + /// + /// Returns the value formated for use in pdf document. + /// + /// Value to turn into a string. + /// The value repsented as a string with no decimals. + internal static string ToPdfStringF0(this double val) + { + return val.ToString("F0", CultureInfo.InvariantCulture); + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/CellAlignmentData.cs b/src/EPPlus.Export.Pdf/Layout/CellAlignmentData.cs new file mode 100644 index 0000000000..68cdd7a0e9 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/CellAlignmentData.cs @@ -0,0 +1,30 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; + +namespace EPPlus.Export.Pdf.Layout +{ + internal class PdfCellAlignmentData + { + public ExcelHorizontalAlignment HorizontalAlignment = ExcelHorizontalAlignment.General; + public ExcelVerticalAlignment VerticalAlignment = ExcelVerticalAlignment.Bottom; + public int Indent = 0; + public bool WrapText = false; + public bool ShrinkToFit = false; + public int TextRotation = 0; + public ExcelReadingOrder TextDirection = ExcelReadingOrder.ContextDependent; + public bool IsVertical = false; + + public PdfCellAlignmentData() { } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/CellFillData.cs b/src/EPPlus.Export.Pdf/Layout/CellFillData.cs new file mode 100644 index 0000000000..bd78f0d7eb --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/CellFillData.cs @@ -0,0 +1,29 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; +using EPPlus.Export.Pdf.Enums; + +namespace EPPlus.Export.Pdf.Layout +{ + internal class PdfCellFillData + { + public string id; + public Color BackgroundColor = Color.Empty; + public ExcelFillStyle PatternStyle = ExcelFillStyle.None; + public Color PatternColor = Color.Black; + //Fill Effects + public PdfCellGradientFillData GradientFillData = null; + public bool enhanceGridLine = false; + public PdfCellFillData() { } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/CellFillGradientData.cs b/src/EPPlus.Export.Pdf/Layout/CellFillGradientData.cs new file mode 100644 index 0000000000..dad5e422e3 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/CellFillGradientData.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Helpers; +using System.Drawing; + +namespace EPPlus.Export.Pdf.Layout +{ + internal class PdfCellGradientFillData + { + public ExcelFillGradientType GradientType; + public Color Color1; + public Color Color2; + public Color Color3; + public double Degree; + public double Top; + public double Bottom; + public double Left; + public double Right; + public double[] matrix; + public double[] coords; + + public override string ToString() + { + return GradientType.ToString() + Color1.ToHexString() + Color2.ToHexString() + Degree + Top + Bottom + Left + Right; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/GridLineData.cs b/src/EPPlus.Export.Pdf/Layout/GridLineData.cs new file mode 100644 index 0000000000..fab9877ebd --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/GridLineData.cs @@ -0,0 +1,30 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.Layout +{ + internal class GridLine + { + public static double Width = 0.125d; + public static double HalfWidth = Width / 2d; + public static double FourthWidth = Width / 4d; + public double X1; + public double Y1; + public double X2; + public double Y2; + + public GridLine(double x1, double y1, double x2, double y2) + { + X1 = x1; Y1 = y1; X2 = x2; Y2 = y2; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/MergedCellCorners.cs b/src/EPPlus.Export.Pdf/Layout/MergedCellCorners.cs new file mode 100644 index 0000000000..8e16f18eec --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/MergedCellCorners.cs @@ -0,0 +1,44 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; + +namespace EPPlus.Export.Pdf.Layout +{ /// + /// Flags that describe which corners of a merged-cell boundary are owned by + /// a particular layout object on the current page. + /// + /// A corner belongs to a layout object when BOTH of its edges land on the page: + /// TopLeft – fromRow and fromCol are within the page range + /// TopRight – fromRow and toCol are within the page range + /// BottomLeft – toRow and fromCol are within the page range + /// BottomRight – toRow and toCol are within the page range + /// + /// Possible combinations: + /// None – interior cell of a large merge; all four edges are + /// clipped by page boundaries. + /// 1 flag – only one corner of the merge lands on this page. + /// 2 flags – merge is exactly 1 row tall → TopLeft|TopRight or BottomLeft|BottomRight + /// merge is exactly 1 col wide → TopLeft|BottomLeft or TopRight|BottomRight + /// All (4 flags)– non-merged cell, or merged cell fully contained on this page. + /// + [Flags] + internal enum MergedCellCorners + { + None = 0, + TopLeft = 1 << 0, // 1 + TopRight = 1 << 1, // 2 + BottomLeft = 1 << 2, // 4 + BottomRight = 1 << 3, // 8 + All = TopLeft | TopRight | BottomLeft | BottomRight + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/MergedCellDrawInfo.cs b/src/EPPlus.Export.Pdf/Layout/MergedCellDrawInfo.cs new file mode 100644 index 0000000000..667702e8cf --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/MergedCellDrawInfo.cs @@ -0,0 +1,22 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.Layout +{ + internal struct MergedCellDrawInfo + { + public double X; + public double Y; + public double Width; + public double Height; + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfBorderData.cs b/src/EPPlus.Export.Pdf/Layout/PdfBorderData.cs new file mode 100644 index 0000000000..5af7cc4015 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfBorderData.cs @@ -0,0 +1,73 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Drawing; +using EPPlus.Export.Pdf.Enums; + +namespace EPPlus.Export.Pdf.Layout +{ + internal class PdfCellBordersData + { + public PdfCellBorderData Top = new PdfCellBorderData(LineType.Top); + public PdfCellBorderData Bottom = new PdfCellBorderData(LineType.Bottom); + public PdfCellBorderData Left = new PdfCellBorderData(LineType.Left); + public PdfCellBorderData Right = new PdfCellBorderData(LineType.Right); + public PdfCellBorderData DiagonalUp = new PdfCellBorderData(LineType.DiagonalUp); + public PdfCellBorderData DiagonalDown = new PdfCellBorderData(LineType.DiagonalDown); + + public PdfCellBordersData() { } + } + + internal enum LineType + { + Top = 0, + Bottom, + Left, + Right, + DiagonalUp, + DiagonalDown + } + + internal class PdfCellBorderData + { + internal const double OuterGridLine = 1d; + internal const double Hair = 0.5d; + internal const double Thin = 0.85d; + internal const double Small = 1.1d; + internal const double Medium = 1.5d; + internal const double Thick = 2.0d; + internal const string NoDash = "[] 0 d"; + internal const string Dotted = "[0 2] 0 d"; + internal const string DashDot = "[4 2 1 2] 0 d"; + internal const string DashDotDot = "[4 2 1 2 1 2] 0 d"; + internal const string Dashed = "[4 3] 0 d"; + internal const string MediumDashDot = "[6 3 2 3] 0 d"; + internal const string MediumDashDotDot = "[6 3 2 3 2 3] 0 d"; + internal const string MediumDashed = "[6 4] 0 d"; + + public ExcelBorderStyle BorderStyle = ExcelBorderStyle.None; + public readonly LineType LineType; + public Color BorderColor = Color.Black; + public double MergedDiagonalWidth = 0d; + public double MergedDiagonalHeight = 0d; + public double Width = 0; + public double Height = 0; + public double X = 0; + public double Y = 0; + public bool IsHeading = false; + + public PdfCellBorderData(LineType LineType) + { + this.LineType = LineType; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCell.cs b/src/EPPlus.Export.Pdf/Layout/PdfCell.cs new file mode 100644 index 0000000000..7ab8ab39fb --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfCell.cs @@ -0,0 +1,36 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Integration; +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.Layout +{ + internal class PdfCellBase + { + public bool Hidden; + public PdfCellAlignmentData ContentAligmnet; + public bool IsPrintTitleRow; + public bool IsPrintTitleCol; + + public string Name { get; set; } + public List TextFragments { get; set; } + public List ShapedTexts { get; set; } + public TextLineCollection TextLines { get; set; } + public string Text { get; set; } + public double TotalTextLength { get; set; } + public double ColumnWidth { get; set; } + public double Width { get; set; } + public double Height { get; set; } + public TextLayoutEngine TextLayoutEngine { get; set; } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellBorderLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellBorderLayout.cs new file mode 100644 index 0000000000..d3a4062680 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellBorderLayout.cs @@ -0,0 +1,93 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; +using EPPlus.Graphics; +using System.Diagnostics; +using System.Drawing; + +namespace EPPlus.Export.Pdf.Layout +{ + [DebuggerDisplay("Border: {Name}")] + internal class PdfCellBorderLayout : Transform + { + public PdfCellBordersData BorderData; + public bool IsMerged = false; + public MergedCellDrawInfo MergedCellInfo; + public MergedCellCorners Corners; + public bool IsPrintTitle; + public string range; + + public PdfCellBorderLayout(bool isMerged, MergedCellCorners corners, MergedCellDrawInfo info, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + : base(x, y - height, width, height, scaleX, scaleY, rotation, parent) + { + Z = 3; + IsMerged = isMerged; + MergedCellInfo = info; + Corners = corners; + BorderData = new PdfCellBordersData(); + + BorderData.Top.X = LocalPosition.X; + BorderData.Top.Y = LocalPosition.Y; + BorderData.Top.Width = Size.X; + BorderData.Top.Height = Size.Y; + + BorderData.Bottom.X = LocalPosition.X; + BorderData.Bottom.Y = LocalPosition.Y; + BorderData.Bottom.Width = Size.X; + BorderData.Bottom.Height = Size.Y; + + BorderData.Left.X = LocalPosition.X; + BorderData.Left.Y = LocalPosition.Y; + BorderData.Left.Width = Size.X; + BorderData.Left.Height = Size.Y; + + BorderData.Right.X = LocalPosition.X; + BorderData.Right.Y = LocalPosition.Y; + BorderData.Right.Width = Size.X; + BorderData.Right.Height = Size.Y; + + BorderData.DiagonalUp.MergedDiagonalWidth = width; + BorderData.DiagonalUp.MergedDiagonalHeight = height; + + BorderData.DiagonalDown.MergedDiagonalWidth = width; + BorderData.DiagonalDown.MergedDiagonalHeight = height; + } + + internal void SetStyle(ExcelBorderStyle topBorderStyle, Color topBorderColor, + ExcelBorderStyle bottomBorderStyle, Color bottomBorderColor, + ExcelBorderStyle leftBorderStyle, Color leftBorderColor, + ExcelBorderStyle rightBorderStyle, Color rightBorderColor, + ExcelBorderStyle diagUpBorderStyle, Color diagUpBorderColor, + ExcelBorderStyle diagdDownBorderStyle, Color diagDownBorderColor) + { + BorderData.Top.BorderStyle = topBorderStyle; + BorderData.Top.BorderColor = topBorderColor; + + BorderData.Bottom.BorderStyle = bottomBorderStyle; + BorderData.Bottom.BorderColor = bottomBorderColor; + + BorderData.Left.BorderStyle = leftBorderStyle; + BorderData.Left.BorderColor = leftBorderColor; + + BorderData.Right.BorderStyle = rightBorderStyle; + BorderData.Right.BorderColor = rightBorderColor; + + BorderData.DiagonalUp.BorderStyle = diagUpBorderStyle; + BorderData.DiagonalUp.BorderColor = diagUpBorderColor; + + BorderData.DiagonalDown.BorderStyle = diagdDownBorderStyle; + BorderData.DiagonalDown.BorderColor = diagDownBorderColor; + } + } +} + diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs new file mode 100644 index 0000000000..17b10557fe --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs @@ -0,0 +1,252 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Graphics; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.Diagnostics; +using Vector2 = EPPlus.Graphics.Geometry.Vector2; + +namespace EPPlus.Export.Pdf.Layout +{ + [DebuggerDisplay("Content: {Name}")] + internal class PdfCellContentLayout : Transform + { + public PdfCellAlignmentData CellAlignmentData; + public bool Clip; + public Rect Clipping; + public bool IsHeaderFooter; + public bool IsHeading; + public bool IsPrintTitle; + public TextLayoutEngine textLayoutEngine; + public TextLineCollection TextLines; + public double LeftTextSpillLength = 0d; + public double RightTextSpillLength = 0d; + private double bottomMargin = 3.5d; //Guessed number + private double rightMargin = 1.4d; //I guessed this one too.. + + public List ShapedTexts { get; set; } + + public PdfCellContentLayout(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfCellBase cell, MergedCellDrawInfo mergedCellInfo, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + : base(x, y-height, width, height, scaleX, scaleY, rotation, parent) + { + Z = 2; + CellAlignmentData = cell.ContentAligmnet; + TextLines = cell.TextLines; + ShapedTexts = cell.ShapedTexts; + textLayoutEngine = cell.TextLayoutEngine; + double totalTextHeight = 0d; + foreach (var line in TextLines) + { + totalTextHeight += line.LargestAscent + line.LargestDescent; + } + double firstLineAscent = TextLines[0].LargestAscent; + double lastLineAscent = TextLines[TextLines.Count - 1].LargestAscent; + LocalPosition = CalculateAlignment(cell.Text, TextLines.LineFragments[0].Width, totalTextHeight, firstLineAscent, lastLineAscent, LocalPosition.X, LocalPosition.Y, cell.Width, height); + } + + public PdfCellContentLayout(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfHeaderFooter headerFooter, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + : base(x, y, width, height, scaleX, scaleY, rotation, parent) + { + Z = 2; + TextLines = headerFooter.Content.TextLines; + ShapedTexts = headerFooter.Content.ShapedTexts; + textLayoutEngine = headerFooter.Content.TextLayoutEngine; + CellAlignmentData = headerFooter.Content.ContentAligmnet; + double totalTextHeight = 0d; + foreach (var line in TextLines) + { + totalTextHeight += line.LargestAscent + line.LargestDescent; + } + var newX = CalculateHorizontalAlignment(TextLines.LineFragments[0].OriginalTextFragment.Text, TextLines[0].Width, LocalPosition.X, width, 0); + LocalPosition = new Vector2 (newX, LocalPosition.Y); + } + + private double CalculateVerticalAlignment(string text, double textHeight, double firstAscent, double lastAscent, double y, double height, double padding) + { + double newY = y; + switch (CellAlignmentData.VerticalAlignment) + { + case ExcelVerticalAlignment.Top: + newY = (y + height) - padding - firstAscent; + break; + case ExcelVerticalAlignment.Center: + newY = y + (height + textHeight - firstAscent - lastAscent) / 2d; + break; + case ExcelVerticalAlignment.Bottom: + newY = y + padding + textHeight - lastAscent; + break; + } + return newY; + } + + private double CalculateHorizontalAlignment(string text, double textLength, double x, double width, double padding) + { + double newX = x; + switch (CellAlignmentData.HorizontalAlignment) + { + case ExcelHorizontalAlignment.Fill: + case ExcelHorizontalAlignment.General: + if (double.TryParse(text, out double value)) + { + newX = x + (width - textLength) - padding; + } + else + { + newX = x + padding; + } + break; + case ExcelHorizontalAlignment.Left: + newX = x + padding; + break; + case ExcelHorizontalAlignment.Center: + newX = x + (width - textLength) / 2d; + break; + case ExcelHorizontalAlignment.Right: + newX = x + (width - textLength) - padding; + break; + } + return newX; + } + + private Vector2 CalculatePositionFromRotation(double textLength, double x, double y) + { + double newX = x; + double newY = y; + if (CellAlignmentData.TextRotation < 0) + { + double rot = CellAlignmentData.TextRotation * System.Math.PI / 180.0; + newX += textLength * (1 - System.Math.Cos(rot)); + newY -= textLength * System.Math.Sin(rot); + } + else if (CellAlignmentData.TextRotation > 0) + { + double rot = CellAlignmentData.TextRotation * System.Math.PI / 180.0; + newX += textLength * (1 - System.Math.Cos(rot)); + } + return new Vector2(newX, newY); + } + + private Vector2 CalculateAlignment(string text, double textLength, double textHeight, double firstLineAscent, double lastLineAscent, double x, double y, double width, double height) + { + if (CellAlignmentData.TextRotation != 0 && !CellAlignmentData.IsVertical) + { + return CalculateRotatedAlignment(textLength, textHeight, firstLineAscent, x, y, width, height); + } + double newX = CalculateHorizontalAlignment(text, textLength, x, width, rightMargin); + double newY = CalculateVerticalAlignment(text, textHeight, firstLineAscent, lastLineAscent, y, height, 0d); + return CalculatePositionFromRotation(textLength, newX, newY); + } + + private Vector2 CalculateRotatedAlignment(double textLength, double textHeight, double firstLineAscent, double x, double y, double width, double height) + { + double ascent = firstLineAscent; + double descent = textHeight - firstLineAscent; + if (descent < 0d) descent = 0d; + double theta = CellAlignmentData.TextRotation * System.Math.PI / 180.0; + double cos = System.Math.Cos(theta); + double sin = System.Math.Sin(theta); + // Bounding box of the rotated block. Reading direction spans [0, textLength]; + // the cross (line-height) direction spans [-descent, ascent]. + double[] gx = { 0d, textLength, 0d, textLength }; + double[] gy = { ascent, ascent, -descent, -descent }; + double minX = double.MaxValue, maxX = double.MinValue, minY = double.MaxValue, maxY = double.MinValue; + for (int i = 0; i < 4; i++) + { + double ux = cos * gx[i] - sin * gy[i]; + double uy = sin * gx[i] + cos * gy[i]; + if (ux < minX) minX = ux; + if (ux > maxX) maxX = ux; + if (uy < minY) minY = uy; + if (uy > maxY) maxY = uy; + } + double blockWidth = maxX - minX; + double blockHeight = maxY - minY; + double bx; + switch (CellAlignmentData.HorizontalAlignment) + { + case ExcelHorizontalAlignment.Left: + bx = x + rightMargin; break; + case ExcelHorizontalAlignment.Right: + bx = x + width - blockWidth - rightMargin; break; + default: // Center / General + bx = x + (width - blockWidth) / 2d; break; + } + double by; + switch (CellAlignmentData.VerticalAlignment) + { + case ExcelVerticalAlignment.Top: + by = y + height - blockHeight - bottomMargin; break; + case ExcelVerticalAlignment.Bottom: + by = y + bottomMargin; break; + default: // Center / Justify / Distributed + by = y + (height - blockHeight) / 2d; break; + } + // Convert the bounding-box lower-left back to the baseline origin the matrix expects. + return new Vector2(bx - minX, by - minY); + } + + // Set clipping to the cell's own bounds. cellY is the top edge (same convention as the constructor). + internal void SetupClipping(double cellX, double cellY, double cellWidth, double cellHeight) + { + Clip = true; + Clipping = new Rect() + { + X = cellX + rightMargin, + Y = cellY - cellHeight, // bottom-left corner in PDF space + Width = cellWidth - rightMargin * 2, + Height = cellHeight + }; + } + + internal void GidsAndCharMap(PdfDictionaries dictionaries) + { + foreach (var tf in ShapedTexts) + { + var usedFonts = tf.UsedFonts; + + foreach (var glyph in tf.ShapedText.Glyphs) + { + if (glyph.FontId >= usedFonts.Count) + continue; + + var font = usedFonts[glyph.FontId]; + + dictionaries.Fonts[font.FullName].Gids.Add(glyph.GlyphId); + dictionaries.Fonts[font.FullName].fontData = font; + + if (!dictionaries.Fonts[font.FullName].charactermappings.ContainsKey(glyph.GlyphId)) + { + var chars = ExtractCharactersForGlyph(glyph, tf.ShapedText.OriginalText); + if (!string.IsNullOrEmpty(chars)) + { + dictionaries.Fonts[font.FullName].charactermappings[glyph.GlyphId] = chars; + } + } + } + } + } + private string ExtractCharactersForGlyph(ShapedGlyph glyph, string textLine) + { + var chars = new System.Text.StringBuilder(); + for (int i = 0; i < glyph.CharCount && glyph.ClusterIndex + i < textLine.Length; i++) + { + chars.Append(textLine[glyph.ClusterIndex + i]); + } + return chars.ToString(); + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs new file mode 100644 index 0000000000..dd037480c9 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs @@ -0,0 +1,172 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Graphics; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; + +namespace EPPlus.Export.Pdf.Layout +{ + [DebuggerDisplay("Cell: {Name}")] + internal class PdfCellLayout : Transform + { + public PdfCellFillData CellFillData; + public double LeftTextSpillLength = 0d; + public double RightTextSpillLength = 0d; + public bool delete = false; + public bool IsHeading = false; + public bool IsPrintTitle = false; + + public PdfCellLayout(double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + : base(x, y - height, width, height, scaleX, scaleY, rotation, parent) + { + Z = 1; + CellFillData = new PdfCellFillData(); + } + + internal void SetFill(Color backgroundColor) + { + CellFillData.PatternStyle = ExcelFillStyle.Solid; + CellFillData.BackgroundColor = backgroundColor; + } + internal void SetPattern(PdfDictionaries dictionaries, ExcelFillStyle patternStyle, Color backgroundColor, Color patternColor) + { + CellFillData.PatternStyle = patternStyle; + CellFillData.BackgroundColor = backgroundColor; + CellFillData.PatternColor = patternColor; + CellFillData.id = AddPatternResourceData(dictionaries.Patterns, CellFillData.PatternStyle.ToString() + CellFillData.PatternColor.ToHexString() + CellFillData.BackgroundColor.ToHexString()); + } + internal void SetGradient(PdfDictionaries dictionaries, ExcelFillGradientType gradientType, Color color1, Color color2, Color color3, double degree, double top, double bottom, double left, double right) + { + CellFillData.GradientFillData = new PdfCellGradientFillData(); + CellFillData.GradientFillData.GradientType = gradientType; + CellFillData.GradientFillData.Color1 = color1; + CellFillData.GradientFillData.Color2 = color2; + CellFillData.GradientFillData.Color3 = color3; + CellFillData.GradientFillData.Degree = degree; + CellFillData.GradientFillData.Top = top; + CellFillData.GradientFillData.Bottom = bottom; + CellFillData.GradientFillData.Left = left; + CellFillData.GradientFillData.Right = right; + CellFillData.id = CellFillData.GradientFillData.ToString() + $"_{Position.X:F4}_{(Position.Y - Size.Y):F4}_{Size.X:F4}_{Size.Y:F4}"; + AddShadingResourceData(dictionaries.Shadings, CellFillData.id); + } + + private string AddPatternResourceData(Dictionary patternResources, string key) + { + if (!patternResources.ContainsKey(key)) + { + int label = 1; + if (patternResources.Count > 0) + { + label = patternResources.Last().Value.labelNumber + 1; + } + var pr = new PdfPatternResource(label, CellFillData); + patternResources.Add(key, pr); + } + return key; + } + + private string AddShadingResourceData(Dictionary shadingResources, string key) + { + if (!shadingResources.ContainsKey(key)) + { + int label = 1; + if (shadingResources.Count > 0) + { + label = shadingResources.Last().Value.labelNumber + 1; + } + var pr = new PdfShadingResource(label, CellFillData); + shadingResources.Add(key, pr); + } + return key; + } + + public void UpdateShadingPositionMatrix(PdfPageSettings pageSettings) + { + if (CellFillData.GradientFillData != null) + { + if (CellFillData.GradientFillData.GradientType == ExcelFillGradientType.Linear) + { + switch (CellFillData.GradientFillData.Degree) + { + case 45d: + CellFillData.GradientFillData.coords = [0, 1, 1, 0]; + break; + case 90d: + CellFillData.GradientFillData.coords = [0, 1, 0, 0]; + break; + case 135d: + CellFillData.GradientFillData.coords = [1, 1, 0, 0]; + break; + case 180d: + CellFillData.GradientFillData.coords = [1, 0, 0, 0]; + break; + case 225d: + CellFillData.GradientFillData.coords = [1, 0, 0, 1]; + break; + case 270d: + CellFillData.GradientFillData.coords = [0, 0, 0, 1]; + break; + case 315d: + CellFillData.GradientFillData.coords = [0, 0, 1, 1]; + break; + case 0d: + default: + CellFillData.GradientFillData.coords = [0, 0, 1, 0]; + break; + } + CellFillData.GradientFillData.matrix = [Size.X, 0, 0, Size.Y, LocalPosition.X, LocalPosition.Y]; + } + else if (CellFillData.GradientFillData.GradientType == ExcelFillGradientType.Path) + { + double x = LocalPosition.X; + double y = LocalPosition.Y; + double width = Size.X; + double height = Size.Y; + var top = CellFillData.GradientFillData.Top; + var bottom = CellFillData.GradientFillData.Bottom; + var left = CellFillData.GradientFillData.Left; + var right = CellFillData.GradientFillData.Right; + double r = 1; + if (top == 0 && bottom == 0 && left == 0 && right == 0) + { + CellFillData.GradientFillData.coords = [0, 1, 0, 0, 1, r]; + } + else if (top == 0 && bottom == 0 && left == 1 && right == 1) + { + CellFillData.GradientFillData.coords = [1, 1, 0, 1, 1, r]; + } + else if (top == 1 && bottom == 1 && left == 0 && right == 0) + { + CellFillData.GradientFillData.coords = [0, 0, 0, 0, 0, r]; + } + else if (top == 1 && bottom == 1 && left == 1 && right == 1) + { + CellFillData.GradientFillData.coords = [1, 0, 0, 1, 0, r]; + } + else if (top == 0.5 && bottom == 0.5 && left == 0.5 && right == 0.5) + { + CellFillData.GradientFillData.coords = [0.5, 0.5, 0, 0.5, 0.5, r]; + } + CellFillData.GradientFillData.matrix = [Size.X, 0, 0, Size.Y, LocalPosition.X, LocalPosition.Y]; + } + } + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs new file mode 100644 index 0000000000..1765ee5c62 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Integration; +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.Layout +{ + internal enum HeaderFooterType + { + First = 0, + Odd = 1, + Even = 2 + } + + internal enum HeaderFooterAlignment + { + Left = 0, + Center = 1, + Right = 2 + } + + internal enum HeaderFooterSection + { + Header = 0, + Footer = 1 + } + + internal class PdfHeaderFooter + { + public HeaderFooterType PageType; + public HeaderFooterAlignment Alignment; + public HeaderFooterSection Section; + public PdfCellBase Content; + public List NumberOfPagesIndexes = new List(); + public List PageNumberIndexes = new List(); + + public PdfHeaderFooter(List textFormats, List pageNumberIndexes, List numberOfPagesIndexes, HeaderFooterType type, HeaderFooterAlignment alignment, HeaderFooterSection section) + { + Content = new PdfCellBase(); + Content.TextFragments = textFormats; + PageNumberIndexes = pageNumberIndexes; + NumberOfPagesIndexes = numberOfPagesIndexes; + PageType = type; + Alignment = alignment; + Section = section; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs new file mode 100644 index 0000000000..2a1d0d9a88 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs @@ -0,0 +1,35 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; +using System.Collections.Generic; +using System.Diagnostics; + +namespace EPPlus.Export.Pdf.Layout +{ + [DebuggerDisplay("{Name}")] + internal class PdfPageLayout : Transform + { + internal List GridLines = new List(); + internal List BorderLines = new List(); + public List PrintTitleGridLines = new List(); + public double HeadingWidth; + public double HeadingHeight; + public double PrintTitleWidth; + public double PrintTitleHeight; + public bool isCommentsPage = false; + + public PdfPageLayout(double x, double y, double width, double height) + : base(x, y, width, height) + { } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/Layout/PdfShapedText.cs b/src/EPPlus.Export.Pdf/Layout/PdfShapedText.cs new file mode 100644 index 0000000000..6162af4f9e --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfShapedText.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.Layout +{ + internal struct PdfShapedText + { + public IFontProvider FontProvider; + public Dictionary FontIdMap; + public List UsedFonts; + public ShapedText ShapedText; + } +} diff --git a/src/EPPlus.Export.Pdf/Resources/PdfDictionaries.cs b/src/EPPlus.Export.Pdf/Resources/PdfDictionaries.cs new file mode 100644 index 0000000000..0cfa817aa1 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Resources/PdfDictionaries.cs @@ -0,0 +1,54 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.Linq; +using EPPlus.Export.Pdf.Settings; + +namespace EPPlus.Export.Pdf.Resources +{ + internal class PdfDictionaries + { + internal readonly Dictionary Fonts = new Dictionary(); + internal readonly Dictionary Patterns = new Dictionary(); + internal readonly Dictionary Shadings = new Dictionary(); + internal Dictionary ShapedProviders = new Dictionary(); + + public void AddFont(PdfPageSettings pageSettings, string FontName, FontSubFamily SubFamily, string Text) + { + var fullFont = FontName + " " + SubFamily.ToString(); + if (!Fonts.ContainsKey(fullFont)) + { + int label = 1; + if (Fonts.Count > 0) + { + label = Fonts.Last().Value.labelNumber + 1; + } + Fonts.Add(fullFont, new PdfFontResource(FontName, SubFamily, label, pageSettings)); + } + var manger = Fonts[fullFont].fontSubsetManager; + manger.AddText(Text); + } + + internal PdfFontResource GetFont(string fontName, FontSubFamily subFamily) + { + var lookUpName = fontName + " " + subFamily.ToString(); + if (!Fonts.ContainsKey(lookUpName)) + { + throw new KeyNotFoundException($"Font: {lookUpName} is missing from dictionary."); + } + return Fonts[lookUpName]; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Resources/PdfFontResource.cs b/src/EPPlus.Export.Pdf/Resources/PdfFontResource.cs new file mode 100644 index 0000000000..a9382a780a --- /dev/null +++ b/src/EPPlus.Export.Pdf/Resources/PdfFontResource.cs @@ -0,0 +1,207 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.DocumentObjects.Fonts; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Export.Pdf.Resources +{ + internal class PdfFontResource : PdfResource + { + internal string fontName; + internal int fontObjectNumber = -1; + internal int CIDFontObjectNumber = -1; + internal int type0FontObjectNumber = -1; + internal int unicodeCMapFontObjectNumber = -1; + internal int embedFontStreamObjectNumber = -1; + internal int fontDescObjectNumber = -1; + internal int fontWidthObjectNumber = -1; + internal int cidSetObjectNumber = -1; + internal OpenTypeFont fontData; + private OpenTypeFontEngine _fontEngine; + private int firstChar = 32; + private int lastChar = 255; + private CIDSystemInfo cidSystemInfo = null; + internal string type0Encoding = "Identity-H"; + internal TextShaper Shaper = null; + internal ShapedText ShapedText; + internal HashSet Subset = new HashSet(); + internal HashSet Gids = new HashSet(); + internal Dictionary charactermappings = new Dictionary(); + internal FontSubsetManager fontSubsetManager; + + public PdfFontResource(string fontName, FontSubFamily subFamily, int labelNumber, PdfPageSettings pageSettings) + : base("F", labelNumber) + { + this.fontName = fontName; + _fontEngine = pageSettings.FontEngine; + fontData = _fontEngine.LoadFont(fontName, subFamily); + fontSubsetManager = new FontSubsetManager(pageSettings.FontEngine, fontData); + } + + //Get the Font Descriptor object to write in PDF. + internal PdfFontDescriptor GetFontDescriptorObject(int objectNumber, int version = 0) + { + int flag = 0; + if (fontData.PostTable.isFixedPitch != 0) + flag |= 1; + if (fontData.GetEnglishFontFamilyName().ToLower().Contains("serif")) + flag |= 1 << 1; + bool isSymbolic = false; + foreach (var sub in fontData.CmapTable.EncodingRecords) + { + if (sub.PlatformId == Fonts.OpenType.Tables.Cmap.Platforms.Windows) + { + if (sub.EncodingId == 0) + { + isSymbolic = true; + break; + } + if (sub.EncodingId == 1 || sub.EncodingId == 10) + { + isSymbolic = false; + break; + } + } + if (sub.PlatformId == Fonts.OpenType.Tables.Cmap.Platforms.Macintosh || sub.PlatformId == Fonts.OpenType.Tables.Cmap.Platforms.Unicode) + { + isSymbolic = true; + break; + } + } + if (isSymbolic) + flag |= 1 << 2; // Symbolic + else + flag |= 1 << 5; // Nonsymbolic + if (fontData.GetEnglishFontFamilyName().ToLower().Contains("script") || fontData.GetEnglishFontFamilyName().ToLower().Contains("cursive")) + flag |= 1 << 3; + if (fontData.PostTable.italicAngle.RawValue != 0 || (fontData.Os2Table.fsSelection & Os2Table.FsSelectionFlags.Italic) != 0) + flag |= 1 << 6; + if (((ushort)fontData.Os2Table.fsSelection & 0x100) != 0) + flag |= 1 << 16; + if (((ushort)fontData.Os2Table.fsSelection & 0x200) != 0) + flag |= 1 << 17; + if (((ushort)fontData.Os2Table.fsSelection & 0x400) != 0) + flag |= 1 << 18; + var fontBBox = new Rect(); + fontBBox.X = fontData.HeadTable.Xmin; + fontBBox.Y = fontData.HeadTable.Ymin; + fontBBox.Width = fontData.HeadTable.Xmax; + fontBBox.Height = fontData.HeadTable.Ymax; + fontDescObjectNumber = objectNumber; + return new PdfFontDescriptor + ( + objectNumber, + fontData.FullName, + flag, + fontBBox, + Convert.ToDouble(fontData.PostTable.italicAngle.FloatValue), + fontData.Os2Table.sTypoAscender, + fontData.Os2Table.sTypoDescender, + 0, + fontData.Os2Table.sCapHeight, + embedFontStreamObjectNumber, + cidSetObjectNumber, + version + ); + } + + //Get the Widths object to write in PDF. + internal PdfFontWidths GetWidthsObject(int objectNumber, int version = 0) + { + List widths = new List(); + int fallbackWidth = fontData.Os2Table.xAvgCharWidth; + var glyphMappings = fontData.CmapTable.GetPreferredSubtable().GetGlyphMappings(); + for (int c = firstChar; c <= lastChar; c++) + { + var gi = glyphMappings.GetGlyphIndex((char)c); + if (gi == 0 && c != 0) + { + int normalizedWidth = (int)System.Math.Round(fallbackWidth / (double)fontData.HeadTable.UnitsPerEm * 1000); + widths.Add(normalizedWidth); + } + else + { + var hhMetric = fontData.HmtxTable.hMetrics[gi ?? 0]; + var advanceWidth = Convert.ToInt16(hhMetric.advanceWidth); + int normalizedWidth = (int)System.Math.Round(advanceWidth / (double)fontData.HeadTable.UnitsPerEm * 1000); + widths.Add(normalizedWidth); + } + } + fontWidthObjectNumber = objectNumber; + return new PdfFontWidths(objectNumber, widths, version); + } + + //Get the Font Object to write in PDF. + internal PdfFont GetFontObject(int objectNumber, int version = 0) + { + fontObjectNumber = objectNumber; + return new PdfFont(objectNumber, fontData.FullName, PdfFontSubType.Type1, firstChar, lastChar, fontWidthObjectNumber, fontDescObjectNumber, PdfFontEncoding.WinAnsiEncoding); + } + + internal PdfCIDFont GetCIDFontObject(int objectNumber, int version = 0) + { + CIDFontObjectNumber = objectNumber; + if (cidSystemInfo == null) + { + cidSystemInfo = new CIDSystemInfo(); + } + cidSystemInfo.Registry = "Adobe"; + cidSystemInfo.Ordering = "Identity"; + cidSystemInfo.Supplement = 0; + return new PdfCIDFont(objectNumber, fontData, Gids, CIDFontSubtype.CIDFontType2, cidSystemInfo, "Identity", fontDescObjectNumber); + } + + internal PdfType0FontDict GetType0FontDictObject(int objectNumber, int version = 0) + { + type0FontObjectNumber = objectNumber; + return new PdfType0FontDict(objectNumber, fontData.FullName, type0Encoding, CIDFontObjectNumber, unicodeCMapFontObjectNumber); + } + + internal PdfToUnicodeCMap GetUnicodeCmapObject(int objectNumber, int version = 0) + { + unicodeCMapFontObjectNumber = objectNumber; + return new PdfToUnicodeCMap(objectNumber, charactermappings); + } + + internal PdfFontStream GetEmbeddedFontStreamObject(int objectNumber, int version = 0) + { + embedFontStreamObjectNumber = objectNumber; + return new PdfFontStream(objectNumber, fontData, version); + } + + internal PdfCidSet GetCidSet(int objectNumber, int version = 0) + { + if (!fontData.IsSubset || Gids.Count == 0) + return null; + int maxGid = Gids.Max(); + int numBytes = (maxGid / 8) + 1; + var cidSet = new byte[numBytes]; + foreach (var gid in Gids) + { + int byteIndex = gid / 8; + int bitIndex = 7 - (gid % 8); + cidSet[byteIndex] |= (byte)(1 << bitIndex); + } + cidSetObjectNumber = objectNumber; + return new PdfCidSet(objectNumber, cidSet, version); + } + } +} diff --git a/src/EPPlus.Export.Pdf/Resources/PdfPatternResource.cs b/src/EPPlus.Export.Pdf/Resources/PdfPatternResource.cs new file mode 100644 index 0000000000..58a4a7aace --- /dev/null +++ b/src/EPPlus.Export.Pdf/Resources/PdfPatternResource.cs @@ -0,0 +1,99 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.DocumentObjects.Patterns; +using EPPlus.Export.Pdf.DocumentObjects; +using EPPlus.Export.Pdf.Enums; + +namespace EPPlus.Export.Pdf.Resources +{ + internal class PdfPatternResource : PdfResource + { + internal int objectNumber; + internal PdfCellFillData CellFillData; + + // All mask-based patterns use an 8x8 tile in pattern space. The mask is the + // single source of geometry, so BBox and the tiling step are 8x8 for every + // pattern. + private static readonly double[] PatternBBox = new double[] { 0d, 0d, 8d, 8d }; + private const double PatternStepX = 8d; + private const double PatternStepY = 8d; + + // The 8x8 pattern space is scaled down to match the physical tile size + // Excel uses (0.75 pt for a full tile, i.e. 0.75 / 8 per pattern unit). + // The scale is positive on both axes: the renderer already mirrors the + // mask in y, so no y-flip is applied here (that would double-flip). + private const double PatternScale = 0.75d / 8d; + private static readonly double[] PatternMatrix = + new double[] { PatternScale, 0d, 0d, PatternScale, 0d, 0d }; + + public PdfPatternResource(int labelNumber, PdfCellFillData cellFillData) + : base("P", labelNumber) + { + CellFillData = cellFillData; + } + + public PdfPattern GetPatternObject(int objectNumber, int version = 0) + { + this.objectNumber = objectNumber; + // None and Solid are not patterns; they are handled as special cases + // elsewhere in the export. + if (CellFillData.PatternStyle == ExcelFillStyle.None || + CellFillData.PatternStyle == ExcelFillStyle.Solid) + { + return null; + } + ExcelPatternMask mask; + if (!TryGetMask(CellFillData.PatternStyle, out mask)) + { + return null; + } + var fill = new PdfPatternMaskFill(mask, CellFillData.PatternColor, CellFillData.BackgroundColor); + var pattern = new PdfTilingPattern(objectNumber, fill, PatternBBox, PatternStepX, PatternStepY, version); + pattern.Matrix = PatternMatrix; + return pattern; + } + + /// + /// Maps an Excel cell fill style to the corresponding 8x8 pattern mask. + /// Returns false for styles that have no mask (e.g. None/Solid, or any + /// style not rendered as a tiling pattern). + /// + private static bool TryGetMask(ExcelFillStyle style, out ExcelPatternMask mask) + { + switch (style) + { + case ExcelFillStyle.DarkGray: mask = ExcelPatternMask.DarkGray; return true; + case ExcelFillStyle.MediumGray: mask = ExcelPatternMask.MediumGray; return true; + case ExcelFillStyle.LightGray: mask = ExcelPatternMask.LightGray; return true; + case ExcelFillStyle.Gray125: mask = ExcelPatternMask.Gray125; return true; + case ExcelFillStyle.Gray0625: mask = ExcelPatternMask.Gray0625; return true; + case ExcelFillStyle.DarkHorizontal: mask = ExcelPatternMask.DarkHorizontal; return true; + case ExcelFillStyle.DarkVertical: mask = ExcelPatternMask.DarkVertical; return true; + case ExcelFillStyle.DarkDown: mask = ExcelPatternMask.DarkDown; return true; + case ExcelFillStyle.DarkUp: mask = ExcelPatternMask.DarkUp; return true; + case ExcelFillStyle.DarkGrid: mask = ExcelPatternMask.DarkGrid; return true; + case ExcelFillStyle.DarkTrellis: mask = ExcelPatternMask.DarkTrellis; return true; + case ExcelFillStyle.LightHorizontal: mask = ExcelPatternMask.LightHorizontal; return true; + case ExcelFillStyle.LightVertical: mask = ExcelPatternMask.LightVertical; return true; + case ExcelFillStyle.LightDown: mask = ExcelPatternMask.LightDown; return true; + case ExcelFillStyle.LightUp: mask = ExcelPatternMask.LightUp; return true; + case ExcelFillStyle.LightGrid: mask = ExcelPatternMask.LightGrid; return true; + case ExcelFillStyle.LightTrellis: mask = ExcelPatternMask.LightTrellis; return true; + default: + mask = ExcelPatternMask.DarkGray; + return false; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/Resources/PdfResource.cs b/src/EPPlus.Export.Pdf/Resources/PdfResource.cs new file mode 100644 index 0000000000..4c2e5d500f --- /dev/null +++ b/src/EPPlus.Export.Pdf/Resources/PdfResource.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.Resources +{ + internal class PdfResource + { + internal readonly string labelPrefix; + internal int labelNumber; + + internal string Label + { + get + { + return labelPrefix + labelNumber; + } + } + + public PdfResource(string labelPrefix, int labelNumber) + { + this.labelPrefix = labelPrefix; + this.labelNumber = labelNumber; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Resources/PdfShadingResource.cs b/src/EPPlus.Export.Pdf/Resources/PdfShadingResource.cs new file mode 100644 index 0000000000..ba565f6b16 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Resources/PdfShadingResource.cs @@ -0,0 +1,61 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.DocumentObjects.Patterns; +using EPPlus.Export.Pdf.DocumentObjects.Shadings; +using EPPlus.Export.Pdf.Enums; +using EPPlus.Export.Pdf.Layout; + +namespace EPPlus.Export.Pdf.Resources +{ + internal class PdfShadingResource : PdfResource + { + internal int objectNumber; + internal PdfCellFillData CellFillData; + + public PdfShadingResource(int labelNumber, PdfCellFillData cellFillData) + : base("Sh", labelNumber) + { + CellFillData = cellFillData; + } + + public PdfShading GetShadingObject(int objectNumber, int version = 0) + { + this.objectNumber = objectNumber; + if (CellFillData.GradientFillData != null) + { + if (CellFillData.GradientFillData.GradientType == ExcelFillGradientType.Linear) + { + var pas = new PdfAxialShading(objectNumber, CellFillData.GradientFillData, version); + pas.Coords = CellFillData.GradientFillData.coords; + return pas; + } + else if (CellFillData.GradientFillData.GradientType == ExcelFillGradientType.Path) + { + var prs = new PdfRadialShading(objectNumber, CellFillData.GradientFillData, version); + prs.Coords = CellFillData.GradientFillData.coords; + return prs; + } + } + return null; + } + + public PdfShadingPattern GetShadingPatternObject(int patternObjectNumber, int shadingObjectNumber, int version = 0) + { + objectNumber = shadingObjectNumber; + var shadingPattern = new PdfShadingPattern(patternObjectNumber, shadingObjectNumber); + shadingPattern.Matrix = CellFillData.GradientFillData.matrix; + return shadingPattern; + } + + } +} diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs new file mode 100644 index 0000000000..d5fdf6486a --- /dev/null +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs @@ -0,0 +1,291 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Settings.PdfPageSizes; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Export.Pdf.Settings +{ + /// + /// Settings object for exporting to PDF. + /// + public class PdfPageSettings + { + private OpenTypeFontEngine _fontEngine; + /// + /// Get the current font engine that is being used by EPPlus. + /// + public OpenTypeFontEngine FontEngine + { + get + { + if(_fontEngine == null) + { + _fontEngine = new OpenTypeFontEngine(x => + { + if(FontDirectories != null && FontDirectories.Any()) + { + foreach(var dir in FontDirectories) + { + if (!System.IO.Directory.Exists(dir)) + { + throw new System.IO.DirectoryNotFoundException($"Font directory not found: {dir}"); + } + x.FontDirectories.Add(dir); + } + x.SearchSystemDirectories = SearchSystemDirectories; + + } + + }); + } + return _fontEngine; + } + } + + /// + /// Add additional folders to search for fonts. + /// + public List FontDirectories = new List(); + + /// + /// If true, epplus will look for fonts in the system directories for installed fonts. c:\windows\fonts + /// + public bool SearchSystemDirectories = true; + + /// + /// If true, subsetted fonts will be embedded into the PDF document. + /// + public bool EmbeddFonts = true; + + /// + /// The order in how to create pages. + /// + public PageOrders PageOrders = PageOrders.DownThenOver; + + /// + /// Set to true to center content on page vertically. + /// + public bool CenterOnPageVertically; + + /// + /// Set to true to center content on page horizontally. + /// + public bool CenterOnPageHorizontally; + + /// + /// Set true to show grid lines. + /// + public bool ShowGridLines = false; + + /// + /// Set true to show row and column headings. + /// + public bool ShowHeadings = false; + + /// + /// Set the range to repeat at the top of the page. + /// + public string RowsToRepeatAtTop = null; + + /// + /// Set the range to repeat to the left of the page. + /// + public string ColumnsToRepeatAtLeft = null; + + /// + /// Set if comments and notes should be included. + /// + public CommentsAndNotes CommentsAndNotes = CommentsAndNotes.None; + + /// + /// Sets how to display errors in cells. + /// + public CellErrors CellErrors = CellErrors.Displayed; + + /// + /// Set the starting page number. + /// + public int FirstPageNumber = 1; + + PdfPageSize _pageSize = PdfPageSize.A4; + /// + /// Set the size of pages. + /// + public PdfPageSize PageSize + { + get + { + return _pageSize; + } + set + { + _pageSize = new PdfPageSize(value.Height, value.Width); + if (value.Height > value.Width) + { + _orientation = Orientations.Portrait; + } + else + { + _orientation = Orientations.Landscape; + } + ContentBounds.CalculateBounds(Margins, PageSize); + } + } + + private Orientations _orientation = Orientations.Portrait; + /// + /// Set the orientation of the pages. + /// + public Orientations Orientation + { + get + { + return _orientation; + } + set + { + if (value == Orientations.Portrait) + { + if (_pageSize.Height < _pageSize.Width) + { + _pageSize = new PdfPageSize(_pageSize.Height, _pageSize.Width); + _orientation = value; + } + } + if (value == Orientations.Landscape) + { + if (_pageSize.Height > _pageSize.Width) + { + _pageSize = new PdfPageSize(_pageSize.Height, _pageSize.Width); + _orientation = value; + } + } + } + } + + private PdfMargins _margins = PdfMargins.Normal; + /// + /// Set the page margins. + /// + public PdfMargins Margins + { + get + { + return _margins; + } + set + { + _margins = value; + ContentBounds.CalculateBounds(Margins, PageSize); + } + } + + private PdfScaling _scaling = PdfScaling.NoScaling; + /// + /// Set the scaling. NOT IMPLEMENTED + /// + public PdfScaling Scaling + { + get + { + return _scaling; + } + set + { + _scaling = value; + } + } + + internal PdfContentBounds ContentBounds = new PdfContentBounds(PdfMargins.Normal, PdfPageSize.A4); + internal string defaultFontName = ""; + + //DEBUG + internal bool Debug = false; + internal bool PrintAsText = false; + } + + /// + /// Orientation of pages. + /// + public enum Orientations + { + /// + /// Portrait orientation. + /// + Portrait, + /// + /// Landscape orientation. + /// + Landscape, + } + + /// + /// Order of pages. + /// + public enum PageOrders + { + /// + /// Order Down then over. + /// + DownThenOver, + /// + /// Order Over then down. + /// + OverThenDown, + } + + /// + /// How comments will be displayed. + /// + public enum CommentsAndNotes + { + /// + /// Comments and Notes will be ignored. + /// + None, + /// + /// Comments and Notes will be displayed on a seprate page at the end. + /// + AtEndOfSheet, + /// + /// Notes will be displayed on the sheet. (Comments will not be shown.) + /// + AsDisplayedOnSheet + } + + /// + /// How errors will be displayed. + /// + public enum CellErrors + { + /// + /// Errors will be displayed + /// + Displayed, + /// + /// Errors will be not displayed + /// + Blank, + /// + /// Errors will be displayed as "--" + /// + Dashed, + /// + /// Errors will be displayed as #N/A + /// + NA, + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfContentBounds.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfContentBounds.cs new file mode 100644 index 0000000000..6d05d77db5 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfContentBounds.cs @@ -0,0 +1,95 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; + +namespace EPPlus.Export.Pdf.Settings.PdfPageSizes +{ + internal class PdfContentBounds : Rect + { + public double HeaderY; + public double FooterY; + public double CenterHeaderX; + public double RightHeaderX; + public double CenterFooterX; + public double RightFooterX; + + private double _top; + private double _bottom; + private double _left; + private double _right; + private double _height; + private double _width; + + public override double Top + { + get { return _top; } + set { _top = value; } + } + + public override double Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + public override double Left + { + get { return _left; } + set { _left = value; } + } + + public override double Right + { + get { return _right; } + set { _right = value; } + } + + public override double Width + { + get { return _width; } + set { _width = value; } + } + + public override double Height + { + get { return _height; } + set { _height = value; } + } + + public PdfContentBounds(PdfMargins margins, PdfPageSize pageSize) + { + CalculateBounds(margins, pageSize); + } + + internal void CalculateBounds(PdfMargins margins, PdfPageSize pageSize) + { + //Content bounds rectangle + Width = pageSize.WidthPu - margins.LeftPu - margins.RightPu; + X = margins.LeftPu; + Left = X; + Right = X + Width; + Y = margins.BottomPu; + Top = pageSize.HeightPu - margins.TopPu; + Bottom = Y; + Height = Top - Bottom; + //Header Footer + var hx = Width / 3d; + FooterY = margins.FooterPu; + CenterFooterX = Left + hx; + RightFooterX = Left + hx * 2; + HeaderY = pageSize.HeightPu - margins.HeaderPu; + CenterHeaderX = Left + hx; + RightHeaderX = Left + hx * 2; + } + } +} diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs new file mode 100644 index 0000000000..1fee87bf8e --- /dev/null +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs @@ -0,0 +1,62 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics.Units; + +namespace EPPlus.Export.Pdf.Settings.PdfPageSizes +{ + public class PdfMargins + { + public double Header { get; set; } = 7.6; + public double Footer { get; set; } = 7.6d; + public double Top { get; set; } = 19.1d; + public double Left { get; set; } = 17.8d; + public double Right { get; set; } = 17.8d; + public double Bottom { get; set; } = 19.1d; + public double HeaderPu { get; private set; } + public double FooterPu { get; private set; } + public double TopPu { get; private set; } + public double LeftPu { get; private set; } + public double RightPu { get; private set; } + public double BottomPu { get; private set; } + + public PdfMargins() + { + TopPu = UnitConversion.MmToPoints(Top); + LeftPu = UnitConversion.MmToPoints(Left); + RightPu = UnitConversion.MmToPoints(Right); + BottomPu = UnitConversion.MmToPoints(Bottom); + HeaderPu = UnitConversion.MmToPoints(Header); + FooterPu = UnitConversion.MmToPoints(Footer); + } + + public PdfMargins(double Top, double Left, double Right, double Bottom, double Header, double Footer) + { + this.Top = Top; + this.Left = Left; + this.Right = Right; + this.Bottom = Bottom; + this.Header = Header; + this.Footer = Footer; + TopPu = UnitConversion.MmToPoints(Top); + LeftPu = UnitConversion.MmToPoints(Left); + RightPu = UnitConversion.MmToPoints(Right); + BottomPu = UnitConversion.MmToPoints(Bottom); + HeaderPu = UnitConversion.MmToPoints(Header); + FooterPu = UnitConversion.MmToPoints(Footer); + } + + public static PdfMargins Normal => new PdfMargins(); + public static PdfMargins Wide => new PdfMargins(25.4d, 25.4d, 25.4d, 25.4d, 12.7d, 12.7d); + public static PdfMargins Narrow => new PdfMargins(19.1d, 6.4d, 6.4d, 19.1d, 7.6d, 7.6d); + } +} diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs new file mode 100644 index 0000000000..8dce84bc52 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs @@ -0,0 +1,42 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics.Units; + +namespace EPPlus.Export.Pdf.Settings.PdfPageSizes +{ + public class PdfPageSize + { + public double Width { get; } + public double Height { get; } + public double WidthPu { get; } + public double HeightPu { get; } + + public PdfPageSize(double width, double height) + { + Width = width; + Height = height; + WidthPu = System.Math.Round( UnitConversion.MmToPoints(width)); + HeightPu = System.Math.Round( UnitConversion.MmToPoints(height)); + } + + public static PdfPageSize A5 => new PdfPageSize(148d, 210d); + public static PdfPageSize A4 => new PdfPageSize(210d, 297d); //(595, 842); + public static PdfPageSize A3 => new PdfPageSize(297d, 420d); //(842, 1191); + public static PdfPageSize B5 => new PdfPageSize(182d, 257d); + public static PdfPageSize B4 => new PdfPageSize(257d, 364d); + public static PdfPageSize Letter => new PdfPageSize(215.9d, 279.4d); //(612, 792); + public static PdfPageSize Legal => new PdfPageSize(215.9d, 355.6d); //(612, 1008); + public static PdfPageSize Statement => new PdfPageSize(139.7d, 215.9d); + public static PdfPageSize Executive => new PdfPageSize(184.2d, 266.7d); + } +} \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfScaling.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfScaling.cs new file mode 100644 index 0000000000..5d48db05c2 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfScaling.cs @@ -0,0 +1,66 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Pdf.Settings.PdfPageSizes +{ + public enum ScalingMode + { + /// + /// Adjust size based on the normal size + /// + AdjustToNormalSize, + /// + /// Adjust size based on number of pages + /// + FitToPages + } + + public class PdfScaling + { + public ScalingMode ScalingMode { get; set; } + + /// + /// Used when is set to AdjustToNormalSize. + /// The scale factor is expressed as a multiplier, where 1.0 represents 100% (no scaling), 0.5 represents 50%, and 2.0 represents 200%. + /// + public double Scale { get; set; } = 1.0; + + /// + /// Used when is set to FitToPages. + /// Scales the content to fit to the specifed number of pages in width. + /// + public int PagesWide { get; set; } = 1; + /// + /// Used when is set to FitToPages. + /// Scales the content to fit to the specifed number of pages in height. + /// + public int PagesTall { get; set; } = 1; + + public PdfScaling(double scale) + { + ScalingMode = ScalingMode.AdjustToNormalSize; + Scale = scale; + } + + public PdfScaling(int pagesWide, int pagesTall) + { + ScalingMode = ScalingMode.FitToPages; + PagesWide = pagesWide; + PagesTall = pagesTall; + } + + public static PdfScaling NoScaling => new PdfScaling(1d); + public static PdfScaling FitSheetToOnePage => new PdfScaling(1, 1); + public static PdfScaling FitAllColumnsOnOnePage => new PdfScaling(1, 0); + public static PdfScaling FitAllRowsOnOnePage => new PdfScaling(0, 1); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/EPPlus.Fonts.OpenType.Benchmarks.csproj b/src/EPPlus.Fonts.OpenType.Benchmarks/EPPlus.Fonts.OpenType.Benchmarks.csproj new file mode 100644 index 0000000000..f1a965d0fb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/EPPlus.Fonts.OpenType.Benchmarks.csproj @@ -0,0 +1,24 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/ExtractCharWidthsBenchmark.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/ExtractCharWidthsBenchmark.cs new file mode 100644 index 0000000000..f37975e81f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/ExtractCharWidthsBenchmark.cs @@ -0,0 +1,74 @@ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Fonts; + +[MemoryDiagnoser] +[SimpleJob(warmupCount: 1, iterationCount: 3)] +public class ExtractCharWidthsBenchmark +{ + private ITextShaper _shaper; + private string _shortText; + private string _mediumText; + private string _longText; + private ShapingOptions _options; + + [GlobalSetup] + public void Setup() + { + var fontFolders = new List { /* your font paths */ }; + var fontEngine = new OpenTypeFontEngine(x => + { + x.SearchSystemDirectories = true; + }); + var font = fontEngine.LoadFont("Calibri"); + _shaper = new TextShaper(fontEngine, font); + _options = ShapingOptions.Default; + + // Short: typical Excel cell + _shortText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; // 56 chars + + // Medium: single paragraph + _mediumText = new string('x', 550); // Simulate 550 char paragraph + + // Long: full 20 paragraphs + _longText = new string('x', 11000); // Simulate 11k chars + } + + [Benchmark] + public double[] ExtractCharWidths_Short() + { + return _shaper.ExtractCharWidths(_shortText, 11f, _options); + } + + [Benchmark] + public double[] ExtractCharWidths_Medium() + { + return _shaper.ExtractCharWidths(_mediumText, 11f, _options); + } + + [Benchmark] + public double[] ExtractCharWidths_Long() + { + return _shaper.ExtractCharWidths(_longText, 11f, _options); + } + + // For comparison: what does Shape() alone allocate? + [Benchmark] + public ShapedText ShapeOnly_Short() + { + return _shaper.Shape(_shortText, _options); + } + + [Benchmark] + public ShapedText ShapeOnly_Medium() + { + return _shaper.Shape(_mediumText, _options); + } + + [Benchmark] + public ShapedText ShapeOnly_Long() + { + return _shaper.Shape(_longText, _options); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheBenchmarks.cs new file mode 100644 index 0000000000..b51dbe68ac --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheBenchmarks.cs @@ -0,0 +1,57 @@ +using BenchmarkDotNet.Attributes; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Benchmarks +{ + /// + /// Separate benchmark class to measure cache performance without ClearCache in IterationSetup + /// + [MemoryDiagnoser] + [SimpleJob(warmupCount: 3, iterationCount: 5)] + public class FontCacheBenchmarks + { + private List _fontFolders; + + [GlobalSetup] + public void Setup() + { + var fontsPath = Path.Combine(System.AppContext.BaseDirectory, "Fonts"); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + } + + _fontFolders = new List { fontsPath }; + + // Pre-load font into cache + OpenTypeFonts.ClearFontCache(); + OpenTypeFonts.LoadFont("Roboto"); + } + + [Benchmark] + public OpenTypeFont Load_FromCache_SingleThread() + { + // This should be extremely fast - just cache lookup + return OpenTypeFonts.LoadFont("Roboto"); + } + + [Benchmark] + public OpenTypeFont[] Load_FromCache_MultipleFonts() + { + // Simulates loading multiple font styles (like for a document) + return new[] + { + OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular), + OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Bold), + OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Italic), + OpenTypeFonts.LoadFont("Roboto", FontSubFamily.BoldItalic) + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheClearingBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheClearingBenchmarks.cs new file mode 100644 index 0000000000..29622a3ca5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/FontCacheClearingBenchmarks.cs @@ -0,0 +1,49 @@ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Fonts; + +/// +/// Benchmarks for repeated cache clearing scenarios +/// +[MemoryDiagnoser] +[SimpleJob(warmupCount: 3, iterationCount: 5)] +public class FontCacheClearingBenchmarks +{ + private List _fontFolders; + + [GlobalSetup] + public void Setup() + { + var fontsPath = Path.Combine(System.AppContext.BaseDirectory, "Fonts"); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + } + + _fontFolders = new List { fontsPath }; + } + + [Benchmark] + public OpenTypeFont Load_Clear_Load_Pattern() + { + // Simulates pattern where cache is cleared between operations + OpenTypeFonts.ClearFontCache(); + var font1 = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + + OpenTypeFonts.ClearFontCache(); + var font2 = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + + return font2; + } + + [Benchmark] + public OpenTypeFont Load_Reuse_Pattern() + { + // Simulates pattern where cache is NOT cleared (optimal) + var font1 = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + var font2 = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + + return font2; + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/FontLoadingBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/FontLoadingBenchmarks.cs new file mode 100644 index 0000000000..703d995c9f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/FontLoadingBenchmarks.cs @@ -0,0 +1,75 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.Benchmarks +{ + [MemoryDiagnoser] + [SimpleJob(warmupCount: 3, iterationCount: 5)] + public class FontLoadingBenchmarks + { + private List _fontFolders; + + [GlobalSetup] + public void Setup() + { + var fontsPath = Path.Combine(System.AppContext.BaseDirectory, "Fonts"); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + } + + _fontFolders = new List { fontsPath }; + } + + [Benchmark] + public OpenTypeFont Load_Roboto_Regular_ColdCache() + { + OpenTypeFonts.ClearFontCache(); // Clear INNE i benchmark + return OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + } + + [Benchmark] + public OpenTypeFont Load_Roboto_Regular_WarmCache() + { + // Load UTAN att cleara - använder cache från GlobalSetup eller warmup + return OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + } + + [Benchmark] + public OpenTypeFont Load_Roboto_Bold_ColdCache() + { + OpenTypeFonts.ClearFontCache(); + return OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Bold); + } + + [Benchmark] + public OpenTypeFont Load_Roboto_Italic_ColdCache() + { + OpenTypeFonts.ClearFontCache(); + return OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Italic); + } + + [Benchmark] + public OpenTypeFont Load_Roboto_BoldItalic_ColdCache() + { + OpenTypeFonts.ClearFontCache(); + return OpenTypeFonts.LoadFont("Roboto", FontSubFamily.BoldItalic); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/Fonts/Roboto-Regular.ttf b/src/EPPlus.Fonts.OpenType.Benchmarks/Fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000..ddf4bfacb3 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Benchmarks/Fonts/Roboto-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/Program.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/Program.cs new file mode 100644 index 0000000000..bb0446d4c0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/Program.cs @@ -0,0 +1,14 @@ +using BenchmarkDotNet.Running; + +namespace EPPlus.Fonts.OpenType.Benchmarks +{ + // Program.cs - Entry point + public class Program + { + public static void Main(string[] args) + { + // Kör alla benchmark-klasser i assembly + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/RichTextBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/RichTextBenchmarks.cs new file mode 100644 index 0000000000..f1181423e7 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/RichTextBenchmarks.cs @@ -0,0 +1,291 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/23/2026 EPPlus Software AB Debug NA benchmarks + 05/06/2026 EPPlus Software AB Use OpenTypeFonts.Configure for font directories + *************************************************************************************************/ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.Benchmarks +{ + [MemoryDiagnoser] + [SimpleJob(warmupCount: 1, iterationCount: 2)] + public class DebugNABenchmarks + { + private const string LoremIpsum20Para = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in.\r\n\r\nFusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id."; + + private TextLayoutEngine _layoutEngine; + + private const double MaxPointWidth = 39d; + private const float FontSize = 11f; + private const string FontFamily = "Roboto"; + + private List _fragments10; + + [GlobalSetup] + public void Setup() + { + Console.WriteLine("========================================"); + Console.WriteLine("DEBUG NA BENCHMARKS - GlobalSetup START"); + Console.WriteLine("========================================"); + + var fontsPath = Path.Combine(AppContext.BaseDirectory, "Fonts"); + Console.WriteLine(string.Format("Fonts directory: {0}", fontsPath)); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException( + string.Format("Fonts directory not found: {0}", fontsPath)); + } + + // Configure the global font system to search the benchmark's local Fonts directory + // exclusively. Must happen before any LoadFont call. + var fontEngine = new OpenTypeFontEngine(cfg => + { + cfg.Reset(); + cfg.FontDirectories.Add(fontsPath); + cfg.SearchSystemDirectories = false; + }); + + + Console.WriteLine("\nAvailable Roboto fonts:"); + foreach (var file in Directory.GetFiles(fontsPath, "Roboto*.ttf")) + { + Console.WriteLine(string.Format(" {0}", Path.GetFileName(file))); + } + + Console.WriteLine("\nLoading Roboto Regular..."); + var font = OpenTypeFonts.LoadFont(FontFamily, FontSubFamily.Regular); + + Console.WriteLine(string.Format("Loaded: {0} {1} ({2} glyphs)", + font.FullName, font.SubFamily, font.GlyfTable.Glyphs.Count)); + + var shaper = new TextShaper(fontEngine, font); + _layoutEngine = new TextLayoutEngine(fontEngine, shaper); + + Console.WriteLine("\nPre-warming font cache (Regular, Bold, Italic)..."); + PrewarmFontCache(); + + Console.WriteLine("\nPreparing 10 test fragments..."); + _fragments10 = new List(); + var measurementFont = new MeasurementFont + { + FontFamily = FontFamily, + Size = FontSize, + Style = MeasurementFontStyles.Regular + }; + + for (int i = 0; i < 10; i++) + { + var tf = new TextFragment + { + Text = LoremIpsum20Para, + }; + tf.RichTextOptions.SetFont(measurementFont); + _fragments10.Add(tf); + } + + Console.WriteLine(string.Format("Prepared {0} fragments, each with {1} chars", + _fragments10.Count, LoremIpsum20Para.Length)); + + Console.WriteLine("\n=== TESTING BENCHMARK 1 ==="); + try + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + var result = TestBenchmark1(); + sw.Stop(); + Console.WriteLine(string.Format("SUCCESS: {0} lines in {1}ms", + result.Count, sw.ElapsedMilliseconds)); + } + catch (Exception ex) + { + Console.WriteLine(string.Format("FAILED: {0}", ex.Message)); + Console.WriteLine(ex.StackTrace); + } + + Console.WriteLine("\n=== TESTING BENCHMARK 2 ==="); + try + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + var result = TestBenchmark2(); + sw.Stop(); + Console.WriteLine(string.Format("SUCCESS: {0} lines in {1}ms", + result.Count, sw.ElapsedMilliseconds)); + } + catch (Exception ex) + { + Console.WriteLine(string.Format("FAILED: {0}", ex.Message)); + Console.WriteLine(ex.StackTrace); + } + + Console.WriteLine("\n========================================"); + Console.WriteLine("GlobalSetup COMPLETE"); + Console.WriteLine("========================================\n"); + } + + private void PrewarmFontCache() + { + var warmupFragments = new List + { + new TextFragment + { + Text = "warmup", + Font = new FontFormatBase + { + Family = FontFamily, + Size = FontSize, + SubFamily = FontSubFamily.Regular + } + }, + new TextFragment + { + Text = "warmup", + Font = new FontFormatBase + { + Family = FontFamily, + Size = 12f, + SubFamily = FontSubFamily.Bold + } + }, + new TextFragment + { + Text = "warmup", + Font = new FontFormatBase + { + Family = FontFamily, + Size = FontSize, + SubFamily = FontSubFamily.Italic + } + } + }; + + var result = _layoutEngine.WrapRichText(warmupFragments, MaxPointWidth); + Console.WriteLine(string.Format(" Cache warmed ({0} lines)", result.Count)); + } + + private List TestBenchmark1() + { + Console.WriteLine(" Wrapping 10 paragraphs sequentially..."); + List allLines = new List(); + for (int i = 0; i < 10; i++) + { + Console.WriteLine(string.Format(" Paragraph {0}...", i + 1)); + var lines = _layoutEngine.WrapRichText( + new List { _fragments10[i] }, + MaxPointWidth + ); + allLines.AddRange(lines); + } + return allLines; + } + + private List TestBenchmark2() + { + Console.WriteLine(" Creating 5 fragments with mixed fonts..."); + var text = LoremIpsum20Para; + int chunkSize = text.Length / 5; + + var fragments = new List + { + new TextFragment + { + Text = text.Substring(0, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = 12f, SubFamily = FontSubFamily.Bold } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 2, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize, SubFamily = FontSubFamily.Italic } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 3, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 4), + Font = new FontFormatBase { Family = FontFamily, Size = 10f } + } + }; + + Console.WriteLine(string.Format(" Created {0} fragments", fragments.Count)); + Console.WriteLine(" Wrapping..."); + return _layoutEngine.WrapRichText(fragments, MaxPointWidth); + } + + [Benchmark] + public List Wrap_10Paragraphs_RichText() + { + List allLines = new List(); + for (int i = 0; i < 10; i++) + { + var lines = _layoutEngine.WrapRichText( + new List { _fragments10[i] }, + MaxPointWidth + ); + allLines.AddRange(lines); + } + return allLines; + } + + [Benchmark] + public List WrapRichText_MixedFonts_LongText() + { + var text = LoremIpsum20Para; + int chunkSize = text.Length / 5; + + var fragments = new List + { + new TextFragment + { + Text = text.Substring(0, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = 12f, SubFamily = FontSubFamily.Bold } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 2, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize, SubFamily = FontSubFamily.Italic } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 3, chunkSize), + Font = new FontFormatBase { Family = FontFamily, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 4), + Font = new FontFormatBase { Family = FontFamily, Size = 10f } + } + }; + + return _layoutEngine.WrapRichText(fragments, MaxPointWidth); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/SubsettingBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/SubsettingBenchmarks.cs new file mode 100644 index 0000000000..985233598d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/SubsettingBenchmarks.cs @@ -0,0 +1,119 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.Benchmarks +{ + [MemoryDiagnoser] + [SimpleJob(warmupCount: 3, iterationCount: 5)] + public class SubsettingBenchmarks + { + private OpenTypeFont _roboto; + private List _fontFolders; + + [GlobalSetup] + public void Setup() + { + var fontsPath = Path.Combine(System.AppContext.BaseDirectory, "Fonts"); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + } + + _fontFolders = new List { fontsPath }; + _roboto = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + } + + [Benchmark] + public OpenTypeFont Subset_SmallText_ABC() + { + return _roboto.CreateSubset("abc"); + } + + [Benchmark] + public OpenTypeFont Subset_SmallText_WithLigatures() + { + return _roboto.CreateSubset("office fit"); + } + + [Benchmark] + public OpenTypeFont Subset_MediumText_Sentence() + { + return _roboto.CreateSubset("The quick brown fox jumps over the lazy dog"); + } + + [Benchmark] + public OpenTypeFont Subset_LargeText_Paragraph() + { + return _roboto.CreateSubset( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris." + ); + } + + [Benchmark] + public OpenTypeFont Subset_Numbers_And_Symbols() + { + return _roboto.CreateSubset("0123456789 +-*/=()[]{},.;:!?@#$%^&"); + } + + [Benchmark] + public OpenTypeFont Subset_Swedish_Characters() + { + return _roboto.CreateSubset("åäöÅÄÖ Sverige Stockholm"); + } + + [Benchmark] + public OpenTypeFont Subset_MixedContent_Realistic() + { + // Simulates a realistic spreadsheet with headers, numbers, and text + return _roboto.CreateSubset( + "Product Name Price Quantity Total " + + "Office Supplies $123.45 100 $12,345.00 " + + "Furniture & Equipment €987.65 50 €49,382.50 " + + "Q1 2024 Revenue Summary" + ); + } + + [Benchmark] + public OpenTypeFont Subset_AllAscii() + { + // All printable ASCII characters (32-126) + var ascii = ""; + for (int i = 32; i <= 126; i++) + { + ascii += (char)i; + } + return _roboto.CreateSubset(ascii); + } + + [Benchmark] + public OpenTypeFont Subset_RepeatedCharacters() + { + // Tests deduplication efficiency + return _roboto.CreateSubset("aaaabbbbccccddddeeeeffffgggg"); + } + + [Benchmark] + public OpenTypeFont Subset_FullAlphabet_LowerAndUpper() + { + return _roboto.CreateSubset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/TextLayoutEngineBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/TextLayoutEngineBenchmarks.cs new file mode 100644 index 0000000000..0502e29325 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/TextLayoutEngineBenchmarks.cs @@ -0,0 +1,274 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/22/2026 EPPlus Software AB New TextLayoutEngine benchmarks + *************************************************************************************************/ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.Benchmarks +{ + /// + /// Benchmarks for new TextLayoutEngine text wrapping performance. + /// Compares with old FontMeasurerTrueType implementation. + /// + [MemoryDiagnoser] + [SimpleJob(warmupCount: 3, iterationCount: 5)] + public class TextLayoutEngineBenchmarks + { + // 20 paragraphs of 'lorem ipsum' - same as TextMeasurementBenchmarks + private const string LoremIpsum20Para = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in.\r\n\r\nFusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh.\r\n\r\nMaecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem.\r\n\r\nInteger congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet.\r\n\r\nSed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus.\r\n\r\nCras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada.\r\n\r\nAliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus.\r\n\r\nNullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris.\r\n\r\nDonec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.\r\n\r\nSuspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.\r\n\r\nCras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.\r\n\r\nQuisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.\r\n\r\nNam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis.\r\n\r\nFusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci.\r\n\r\nVivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida.\r\n\r\nIn in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum.\r\n\r\nDonec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet.\r\n\r\nInterdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo.\r\n\r\nDonec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum.\r\n\r\nNunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; + + private TextLayoutEngine _layoutEngine; + // private FontMeasurerTrueType _oldMeasurer; + + private const double MaxPixelWidth = 52d; + private const double MaxPointWidth = 39d; // 52 pixels ≈ 39 points (at 96 DPI) + private const float FontSize = 11f; + private const string Family = "Roboto"; + + private List _fragments10; + private List _texts10; + private List _fonts10; + + //[GlobalSetup] + //public void Setup() + //{ + // // Setup old measurer + // _oldMeasurer = new FontMeasurerTrueType(); + // _oldMeasurer.SetFont(FontSize, Family); + + // var fontsPath = Path.Combine(AppContext.BaseDirectory, "Fonts"); + + // if (!Directory.Exists(fontsPath)) + // { + // throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + // } + + // var fontFolders = new List { fontsPath }; + + // // Setup new layout engine + // var font = OpenTypeFonts.LoadFont(Family, FontSubFamily.Regular); + // var shaper = new TextShaper(font); + // _layoutEngine = new TextLayoutEngine(shaper); + + // // Prepare 100 copies of the long text + // _fragments10 = new List(); + // _texts10 = new List(); + // _fonts10 = new List(); + + // var OpenTypeFontInfoBase = new OpenTypeFontInfoBase + // { + // Family = Family, + // Size = FontSize, + // SubFamily = OpenTypeFontInfoBaseSubFamilys.Regular + // }; + + // for (int i = 0; i < 10; i++) + // { + // _texts10.Add(LoremIpsum20Para); + // _fonts10.Add(measurementFont); + // _fragments10.Add(new TextFragment + // { + // Text = LoremIpsum20Para, + // Font = measurementFont + // }); + // } + //} + + //#region Old Implementation Benchmarks (Baseline) + + //[Benchmark(Baseline = true)] + //public List Old_Wrap_SingleParagraph() + //{ + // return _oldMeasurer.MeasureAndWrapText(LoremIpsum20Para, MaxPixelWidth); + //} + + //[Benchmark] + //public List Old_Wrap_10Paragraphs_Sequential() + //{ + // List wrapped = new List(); + // foreach (string text in _texts10) + // { + // wrapped = _oldMeasurer.MeasureAndWrapText(text, MaxPixelWidth); + // } + // return wrapped; + //} + + //[Benchmark] + //public List Old_Wrap_10Paragraphs_MultipleFragments() + //{ + // return _oldMeasurer.WrapMultipleTextFragments(_texts10, _fonts10, MaxPixelWidth); + //} + + //[Benchmark] + //public List Old_Wrap_ShortText() + //{ + // var shortText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + // return _oldMeasurer.MeasureAndWrapText(shortText, MaxPixelWidth); + //} + + //[Benchmark] + //public List Old_Wrap_WideColumn() + //{ + // return _oldMeasurer.MeasureAndWrapText(LoremIpsum20Para, 200d); + //} + + //[Benchmark] + //public List Old_Wrap_NarrowColumn() + //{ + // return _oldMeasurer.MeasureAndWrapText(LoremIpsum20Para, 30d); + //} + + //#endregion + + #region New Implementation Benchmarks + + [Benchmark] + public List New_Wrap_SingleParagraph() + { + return _layoutEngine.WrapText(LoremIpsum20Para, FontSize, MaxPointWidth); + } + + [Benchmark] + public List New_Wrap_10Paragraphs_Sequential() + { + List wrapped = new List(); + foreach (string text in _texts10) + { + wrapped = _layoutEngine.WrapText(text, FontSize, MaxPointWidth); + } + return wrapped; + } + + [Benchmark] + public double[] OnlyExtractWidths() + { + var fontsPath = Path.Combine(AppContext.BaseDirectory, "Fonts"); + var fontEngine = new OpenTypeFontEngine(x => + { + x.FontDirectories.Add(fontsPath); + x.SearchSystemDirectories = false; + }); + var font = fontEngine.LoadFont(Family, FontSubFamily.Regular); + var shaper = new TextShaper(fontEngine, font); + return shaper.ExtractCharWidths(LoremIpsum20Para, FontSize, ShapingOptions.Default); + } + + [Benchmark] + public List New_Wrap_10Paragraphs_RichText() + { + // Note: This wraps each text individually, not as one concatenated text + // (matching old behavior more closely than wrapping all as single rich text) + List allLines = new List(); + foreach (var fragment in _fragments10) + { + var lines = _layoutEngine.WrapRichText(new List { fragment }, MaxPointWidth); + allLines.AddRange(lines); + } + return allLines; + } + + [Benchmark] + public List New_Wrap_ShortText() + { + var shortText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + return _layoutEngine.WrapText(shortText, FontSize, MaxPointWidth); + } + + [Benchmark] + public List New_Wrap_WideColumn() + { + return _layoutEngine.WrapText(LoremIpsum20Para, FontSize, 150d); // ~200 pixels in points + } + + [Benchmark] + public List New_Wrap_NarrowColumn() + { + return _layoutEngine.WrapText(LoremIpsum20Para, FontSize, 22.5d); // ~30 pixels in points + } + + #endregion + + #region Rich Text Specific Benchmarks + + [Benchmark] + public List New_WrapRichText_MixedFonts_ShortText() + { + var fragments = new List + { + new TextFragment + { + Text = "Lorem ipsum ", + Font = new FontFormatBase { Family = Family, Size = FontSize } + }, + new TextFragment + { + Text = "dolor sit amet, ", + Font = new FontFormatBase { Family = Family, Size = 12f, SubFamily = FontSubFamily.Bold } + }, + new TextFragment + { + Text = "consectetur adipiscing elit.", + Font = new FontFormatBase { Family = Family, Size = FontSize } + } + }; + + return _layoutEngine.WrapRichText(fragments, MaxPointWidth); + } + + [Benchmark] + public List New_WrapRichText_MixedFonts_LongText() + { + // Split lorem ipsum into 5 fragments with different formatting + var text = LoremIpsum20Para; + int chunkSize = text.Length / 5; + + var fragments = new List + { + new TextFragment + { + Text = text.Substring(0, chunkSize), + Font = new FontFormatBase { Family = Family, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize, chunkSize), + Font = new FontFormatBase { Family = Family, Size = 12f, SubFamily = FontSubFamily.Bold } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 2, chunkSize), + Font = new FontFormatBase { Family = Family, Size = FontSize, SubFamily = FontSubFamily.Italic } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 3, chunkSize), + Font = new FontFormatBase { Family = Family, Size = FontSize } + }, + new TextFragment + { + Text = text.Substring(chunkSize * 4), + Font = new FontFormatBase { Family = Family, Size = 10f } + } + }; + + return _layoutEngine.WrapRichText(fragments, MaxPointWidth); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/TextMeasurementBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/TextMeasurementBenchmarks.cs new file mode 100644 index 0000000000..cff7d6e363 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/TextMeasurementBenchmarks.cs @@ -0,0 +1,123 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.FontCache; +using OfficeOpenXml.Interfaces.Drawing.Text; +using System.Collections.Generic; + +namespace EPPlus.Fonts.Benchmarks +{ + /// + /// Benchmarks for text measurement and wrapping performance. + /// Tests measure and wrap operations on varying text lengths. + /// + [MemoryDiagnoser] + [SimpleJob(warmupCount: 3, iterationCount: 5)] + public class TextMeasurementBenchmarks + { + //// 20 paragraphs of 'lorem ipsum' + //// 1706 words, 11,800 characters (with whitespace), 10,095 characters without + //private const string LoremIpsum20Para = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in.\r\n\r\nFusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh.\r\n\r\nMaecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem.\r\n\r\nInteger congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet.\r\n\r\nSed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus.\r\n\r\nCras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada.\r\n\r\nAliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus.\r\n\r\nNullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris.\r\n\r\nDonec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.\r\n\r\nSuspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.\r\n\r\nCras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.\r\n\r\nQuisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.\r\n\r\nNam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis.\r\n\r\nFusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci.\r\n\r\nVivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida.\r\n\r\nIn in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum.\r\n\r\nDonec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet.\r\n\r\nInterdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo.\r\n\r\nDonec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum.\r\n\r\nNunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; // INSERT LOREM IPSUM HERE + + ////private FontMeasurerTrueType _textMeasurer; + //private const double MaxPixelWidth = 52d; + //private const double FontSize = 11d; + //private const string FontFamily = "Aptos Narrow"; + + //private List _texts100; + //private List _fonts100; + + //[GlobalSetup] + //public void Setup() + //{ + // _textMeasurer = new FontMeasurerTrueType(); + // _textMeasurer.SetFont(FontSize, FontFamily); + + // // Prepare 100 copies of the long text + // _texts100 = new List(); + // _fonts100 = new List(); + + // var font = new MeasurementFont + // { + // FontFamily = FontFamily, + // Size = (float)FontSize, + // Style = MeasurementFontStyles.Regular + // }; + + // for (int i = 0; i < 100; i++) + // { + // _texts100.Add(LoremIpsum20Para); + // _fonts100.Add(font); + // } + //} + + //[Benchmark] + //public List Wrap_SingleParagraph() + //{ + // // Baseline: wrap a single 20-paragraph text + // return _textMeasurer.MeasureAndWrapText(LoremIpsum20Para, MaxPixelWidth); + //} + + //[Benchmark] + //public List Wrap_100Paragraphs_Sequential() + //{ + // // Original test: wrap 100 texts sequentially + // List wrapped = new List(); + + // foreach (string text in _texts100) + // { + // wrapped = _textMeasurer.MeasureAndWrapText(text, MaxPixelWidth); + // } + + // return wrapped; + //} + + //[Benchmark] + //public List Wrap_100Paragraphs_MultipleFragments() + //{ + // // Original multi-fragment test: wrap 100 texts in one call + // return _textMeasurer.WrapMultipleTextFragments(_texts100, _fonts100, MaxPixelWidth); + //} + + //[Benchmark] + //public List Wrap_ShortText() + //{ + // // Baseline: wrap a short text (first paragraph only) + // var shortText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + // return _textMeasurer.MeasureAndWrapText(shortText, MaxPixelWidth); + //} + + //[Benchmark] + //public List Wrap_MediumText() + //{ + // // Medium length text (5 paragraphs, ~2950 chars) + // var mediumText = ""; // INSERT FIRST 5 PARAGRAPHS HERE + // return _textMeasurer.MeasureAndWrapText(mediumText, MaxPixelWidth); + //} + + //[Benchmark] + //public List Wrap_WideColumn() + //{ + // // Same text, but wider column (less wrapping needed) + // return _textMeasurer.MeasureAndWrapText(LoremIpsum20Para, 200d); + //} + + //[Benchmark] + //public List Wrap_NarrowColumn() + //{ + // // Same text, but narrower column (more wrapping needed) + // return _textMeasurer.MeasureAndWrapText(LoremIpsum20Para, 30d); + //} + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Benchmarks/TextShapingBenchmarks.cs b/src/EPPlus.Fonts.OpenType.Benchmarks/TextShapingBenchmarks.cs new file mode 100644 index 0000000000..e8b72a80a8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Benchmarks/TextShapingBenchmarks.cs @@ -0,0 +1,59 @@ +using BenchmarkDotNet.Attributes; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Benchmarks +{ + [MemoryDiagnoser] // Shows memory allocations + [SimpleJob(warmupCount: 3, iterationCount: 5)] // 3 warmups, 5 measurements + public class TextShapingBenchmarks + { + private OpenTypeFont _roboto; + private OpenTypeFontEngine _engine; + private TextShaper _shaper; + + [GlobalSetup] // Runs once before all benchmarks + public void Setup() + { + var fontsPath = Path.Combine(AppContext.BaseDirectory, "Fonts"); + _engine = new OpenTypeFontEngine(x => + { + x.FontDirectories.Add(fontsPath); + x.SearchSystemDirectories = false; + }); + + if (!Directory.Exists(fontsPath)) + { + throw new DirectoryNotFoundException($"Fonts directory not found: {fontsPath}"); + } + + var fontFolders = new List { fontsPath }; + _roboto = _engine.LoadFont("Roboto", FontSubFamily.Regular); + _shaper = new TextShaper(_engine, _roboto); + } + + [Benchmark] + public ShapedText Shape_ShortText() + { + return _shaper.Shape("Hello"); + } + + [Benchmark] + public ShapedText Shape_WithLigatures() + { + return _shaper.Shape("office fit"); + } + + [Benchmark] + public ShapedText Shape_LongText() + { + return _shaper.Shape("The quick brown fox jumps over the lazy dog. Office 2024."); + } + + [Benchmark] + public ShapedText Shape_LotsOfLigatures() + { + return _shaper.Shape("office efficientaffinityuffice"); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/DataHolders/TextLineSimpleTests.cs b/src/EPPlus.Fonts.OpenType.Tests/DataHolders/TextLineSimpleTests.cs new file mode 100644 index 0000000000..eb9bda6daa --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/DataHolders/TextLineSimpleTests.cs @@ -0,0 +1,118 @@ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Tests.DataHolders +{ + [TestClass] + public class TextLineSimpleTests + { + [TestMethod] + public void TestLineFragmentAbstraction() + { + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + + var fragments = GetTextFragments(); + + var layout = OpenTypeFonts.GetTextLayoutEngineForFont(fragments[0].Font); + var wrappedLines = layout.WrapRichTextLines(fragments, maxSizePoints); + var wrappedCollection = layout.WrapRichTextLineCollection(fragments, maxSizePoints); + + + } + + [TestMethod] + public void TestLineFragmentSeeWhatLinesUseWhatRichText() + { + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + + var fragments = GetTextFragments(); + + fragments[4].RichTextOptions.FontColor = Color.DarkRed; + + var layout = OpenTypeFonts.GetTextLayoutEngineForFont(fragments[0].Font); + + var wrappedLines = layout.WrapRichTextLines(fragments, maxSizePoints); + var wrappedCollection = layout.WrapRichTextLineCollection(fragments, maxSizePoints); + + var lines = wrappedCollection.GetTextLinesThatUse(fragments[4]); + var specificFragments = wrappedCollection.GetLineFragmentsThatUse(fragments[4]); + var lineIndicies = wrappedCollection.GetLineNumbersThatUse(fragments[4]); + + Assert.AreEqual(lines[0].LineFragments[1], specificFragments[0]); + Assert.AreEqual(fragments[4], wrappedCollection.LineFragments[6].OriginalTextFragment); + Assert.AreEqual(Color.DarkRed, ((TextFragment)wrappedCollection.LineFragments[6].OriginalTextFragment).RichTextOptions.FontColor); + + var expectedArr = new int[] { 3, 4 }; + expectedArr.SequenceCompareTo(lineIndicies); + } + + List GetTextFragments() + { + List lstOfRichText = new() { "TextBox\r\na\r\n", "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + + var font1 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + var font6 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 24, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new() { font1, font2, font3, font4, font5, font6 }; + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + return fragments; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.csproj b/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.csproj new file mode 100644 index 0000000000..5df411d299 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.csproj @@ -0,0 +1,80 @@ + + + net8.0 + latest + enable + enable + true + True + EPPlus.Fonts.OpenType.Tests.snk + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + diff --git a/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.snk b/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.snk new file mode 100644 index 0000000000..ae148f9f28 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/EPPlus.Fonts.OpenType.Tests.snk differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/CustomFontProviderTests.cs b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/CustomFontProviderTests.cs new file mode 100644 index 0000000000..a824db199a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/CustomFontProviderTests.cs @@ -0,0 +1,346 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/24/2026 EPPlus Software AB CustomFontProvider unit tests + *************************************************************************************************/ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.FallbackFonts +{ + [TestClass] + public class CustomFontProviderTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + private OpenTypeFont _robotoFont; + private OpenTypeFont _notoEmojiFont; + private OpenTypeFont _notoMathFont; + + // U+1F600 = 😀 (Grinning Face) - present in NotoEmoji, absent in Roboto + private const uint EmojiCodePoint = 0x1F600; + // U+0041 = 'A' - present in Roboto (and most text fonts) + private const uint LatinA = 0x0041; + // U+2A0C = ⨌ (Quadruple Integral) - present in Noto Sans Math, absent in Roboto and NotoEmoji + private const uint IntegralCodePoint = 0x2A0C; + // U+F0000 = Private Use Area - unlikely to be in any standard font + private const uint PrivateUseCodePoint = 0xF0000; + + [TestInitialize] + public void TestSetup() + { + _robotoFont = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + _notoEmojiFont = TestFolderEngine.LoadFont("Noto Emoji", FontSubFamily.Regular); + _notoMathFont = TestFolderEngine.LoadFont("Noto Sans Math", FontSubFamily.Regular); + } + + #region Constructor Tests + + [TestMethod] + public void Constructor_WithValidFont_ShouldSetPrimaryFont() + { + // Act + var provider = new CustomFontProvider(_robotoFont); + + // Assert + Assert.AreEqual(_robotoFont, provider.PrimaryFont); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void Constructor_WithNull_ShouldThrowArgumentNullException() + { + // Act + new CustomFontProvider(null); + } + + #endregion + + #region AddFallback Tests + + [TestMethod] + public void AddFallback_WithValidFont_ShouldBeIncludedInGetAllFonts() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + + // Act + provider.AddFallback(_notoEmojiFont); + var allFonts = provider.GetAllFonts().ToList(); + + // Assert + Assert.AreEqual(2, allFonts.Count, "Should have primary + 1 fallback"); + Assert.AreEqual(_robotoFont, allFonts[0], "First should be primary font"); + Assert.AreEqual(_notoEmojiFont, allFonts[1], "Second should be fallback font"); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AddFallback_WithNull_ShouldThrowArgumentNullException() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + + // Act + provider.AddFallback(null); + } + + [TestMethod] + public void AddFallback_MultipleFonts_ShouldPreserveOrder() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + + // Act + provider.AddFallback(_notoEmojiFont); + provider.AddFallback(_robotoFont); // Same font again, to test ordering + var allFonts = provider.GetAllFonts().ToList(); + + // Assert + Assert.AreEqual(3, allFonts.Count, "Should have primary + 2 fallbacks"); + Assert.AreEqual(_robotoFont, allFonts[0], "First should be primary"); + Assert.AreEqual(_notoEmojiFont, allFonts[1], "Second should be first added fallback"); + Assert.AreEqual(_robotoFont, allFonts[2], "Third should be second added fallback"); + } + + #endregion + + #region TryGetGlyphFont - Primary Font Tests + + [TestMethod] + public void TryGetGlyphFont_LatinChar_ShouldUsePrimaryFont() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Act + bool found = provider.TryGetGlyphFont(LatinA, out var font, out var glyphId); + + // Assert + Assert.IsTrue(found, "Should find glyph for 'A'"); + Assert.AreEqual(_robotoFont, font, "Should use primary font for Latin chars"); + Assert.AreNotEqual((ushort)0, glyphId, "GlyphId should not be .notdef"); + } + + [TestMethod] + public void TryGetGlyphFont_CharInBothFonts_ShouldPreferPrimaryFont() + { + // Arrange - both Roboto and NotoEmoji might have basic chars, + // but primary should always be preferred + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Act + bool found = provider.TryGetGlyphFont(LatinA, out var font, out var glyphId); + + // Assert + Assert.IsTrue(found); + Assert.AreEqual(_robotoFont, font, "Primary font should always be preferred when it has the glyph"); + } + + #endregion + + #region TryGetGlyphFont - Fallback Tests + + [TestMethod] + public void TryGetGlyphFont_EmojiNotInPrimary_ShouldUseFallbackFont() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Verify preconditions: Roboto should NOT have the emoji glyph + bool robotoHasEmoji = _robotoFont.CmapTable.TryGetGlyphId(EmojiCodePoint, out _); + Assert.IsFalse(robotoHasEmoji, "Precondition: Roboto should not contain emoji U+1F600"); + + // Verify preconditions: NotoEmoji SHOULD have the emoji glyph + bool notoHasEmoji = _notoEmojiFont.CmapTable.TryGetGlyphId(EmojiCodePoint, out _); + Assert.IsTrue(notoHasEmoji, "Precondition: NotoEmoji should contain emoji U+1F600"); + + // Act + bool found = provider.TryGetGlyphFont(EmojiCodePoint, out var font, out var glyphId); + + // Assert + Assert.IsTrue(found, "Should find emoji glyph in fallback font"); + Assert.AreEqual(_notoEmojiFont, font, "Should return NotoEmoji as the fallback font"); + Assert.AreNotEqual((ushort)0, glyphId, "GlyphId should not be .notdef"); + } + + [TestMethod] + public void TryGetGlyphFont_EmojiWithMultipleFallbacks_ShouldUseFirstMatchingFallback() + { + // Arrange - add Roboto (no emoji) first, then NotoEmoji (has emoji) + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_robotoFont); // First fallback: also no emoji + provider.AddFallback(_notoEmojiFont); // Second fallback: has emoji + + // Act + bool found = provider.TryGetGlyphFont(EmojiCodePoint, out var font, out var glyphId); + + // Assert + Assert.IsTrue(found, "Should find emoji in second fallback"); + Assert.AreEqual(_notoEmojiFont, font, "Should return NotoEmoji (second fallback), not Roboto (first fallback)"); + Assert.AreNotEqual((ushort)0, glyphId); + } + + [TestMethod] + public void TryGetGlyphFont_MathSymbol_ShouldUseThirdFallback() + { + // Arrange - three-level fallback chain: Roboto → NotoEmoji → NotoSansMath + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + provider.AddFallback(_notoMathFont); + + // Verify preconditions + bool robotoHasMath = _robotoFont.CmapTable.TryGetGlyphId(IntegralCodePoint, out _); + Assert.IsFalse(robotoHasMath, "Precondition: Roboto should not contain ∫ (U+222B)"); + + bool emojiHasMath = _notoEmojiFont.CmapTable.TryGetGlyphId(IntegralCodePoint, out _); + Assert.IsFalse(emojiHasMath, "Precondition: NotoEmoji should not contain ∫ (U+222B)"); + + bool mathHasMath = _notoMathFont.CmapTable.TryGetGlyphId(IntegralCodePoint, out _); + Assert.IsTrue(mathHasMath, "Precondition: Noto Sans Math should contain ∫ (U+222B)"); + + // Act + bool found = provider.TryGetGlyphFont(IntegralCodePoint, out var font, out var glyphId); + + // Assert + Assert.IsTrue(found, "Should find ∫ in third fallback (Noto Sans Math)"); + Assert.AreEqual(_notoMathFont, font, "Should return Noto Sans Math as the resolving font"); + Assert.AreNotEqual((ushort)0, glyphId, "GlyphId should not be .notdef"); + } + + [TestMethod] + public void TryGetGlyphFont_ThreeFallbacks_EachFontResolvesItsOwnDomain() + { + // Arrange - full chain: Roboto → NotoEmoji → NotoSansMath + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + provider.AddFallback(_notoMathFont); + + // Act & Assert - Latin 'A' should resolve from primary (Roboto) + bool foundLatin = provider.TryGetGlyphFont(LatinA, out var latinFont, out var latinGlyphId); + Assert.IsTrue(foundLatin); + Assert.AreEqual(_robotoFont, latinFont, "Latin 'A' should come from Roboto (primary)"); + Assert.AreNotEqual((ushort)0, latinGlyphId); + + // Act & Assert - Emoji should resolve from first fallback (NotoEmoji) + bool foundEmoji = provider.TryGetGlyphFont(EmojiCodePoint, out var emojiFont, out var emojiGlyphId); + Assert.IsTrue(foundEmoji); + Assert.AreEqual(_notoEmojiFont, emojiFont, "Emoji should come from NotoEmoji (1st fallback)"); + Assert.AreNotEqual((ushort)0, emojiGlyphId); + + // Act & Assert - Math symbol should resolve from second fallback (NotoSansMath) + bool foundMath = provider.TryGetGlyphFont(IntegralCodePoint, out var mathFont, out var mathGlyphId); + Assert.IsTrue(foundMath); + Assert.AreEqual(_notoMathFont, mathFont, "∫ should come from Noto Sans Math (2nd fallback)"); + Assert.AreNotEqual((ushort)0, mathGlyphId); + + // Act & Assert - Unknown code point should fail gracefully + bool foundUnknown = provider.TryGetGlyphFont(PrivateUseCodePoint, out var unknownFont, out var unknownGlyphId); + Assert.IsFalse(foundUnknown); + Assert.AreEqual(_robotoFont, unknownFont, "Not found should return primary font"); + Assert.AreEqual((ushort)0, unknownGlyphId); + } + + #endregion + + #region TryGetGlyphFont - Not Found Tests + + [TestMethod] + public void TryGetGlyphFont_CharNotInAnyFont_ShouldReturnFalseWithPrimaryFont() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Act + bool found = provider.TryGetGlyphFont(PrivateUseCodePoint, out var font, out var glyphId); + + // Assert + Assert.IsFalse(found, "Should not find glyph in Private Use Area"); + Assert.AreEqual(_robotoFont, font, "Should return primary font even when not found"); + Assert.AreEqual((ushort)0, glyphId, "GlyphId should be .notdef (0)"); + } + + [TestMethod] + public void TryGetGlyphFont_NoFallbacks_CharNotInPrimary_ShouldReturnFalse() + { + // Arrange - no fallbacks added at all + var provider = new CustomFontProvider(_robotoFont); + + // Act + bool found = provider.TryGetGlyphFont(EmojiCodePoint, out var font, out var glyphId); + + // Assert + Assert.IsFalse(found, "Should not find emoji when no fallbacks are configured"); + Assert.AreEqual(_robotoFont, font, "Should still return primary font"); + Assert.AreEqual((ushort)0, glyphId, "Should return .notdef"); + } + + #endregion + + #region GetAllFonts Tests + + [TestMethod] + public void GetAllFonts_NoFallbacks_ShouldReturnOnlyPrimary() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + + // Act + var allFonts = provider.GetAllFonts().ToList(); + + // Assert + Assert.AreEqual(1, allFonts.Count, "Should only contain primary font"); + Assert.AreEqual(_robotoFont, allFonts[0]); + } + + [TestMethod] + public void GetAllFonts_WithFallbacks_ShouldReturnPrimaryFirstThenFallbacks() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Act + var allFonts = provider.GetAllFonts().ToList(); + + // Assert + Assert.AreEqual(2, allFonts.Count); + Assert.AreEqual(_robotoFont, allFonts[0], "Primary font should be first"); + Assert.AreEqual(_notoEmojiFont, allFonts[1], "Fallback should come after primary"); + } + + [TestMethod] + public void GetAllFonts_CalledMultipleTimes_ShouldReturnConsistentResults() + { + // Arrange + var provider = new CustomFontProvider(_robotoFont); + provider.AddFallback(_notoEmojiFont); + + // Act + var firstCall = provider.GetAllFonts().ToList(); + var secondCall = provider.GetAllFonts().ToList(); + + // Assert + Assert.AreEqual(firstCall.Count, secondCall.Count); + for (int i = 0; i < firstCall.Count; i++) + { + Assert.AreEqual(firstCall[i], secondCall[i], $"Font at index {i} should be the same across calls"); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/DefaultPrimaryFontTests.cs b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/DefaultPrimaryFontTests.cs new file mode 100644 index 0000000000..bcf5b2b5ee --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/DefaultPrimaryFontTests.cs @@ -0,0 +1,83 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/27/2026 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontResolver; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.FallbackFonts +{ + [TestClass] + public class DefaultPrimaryFontTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + private static readonly string UnknownFont = "ThisFontDoesNotExist_XYZ"; + + private static DefaultFontResolver CreateIsolatedResolver() + { + // No directories, no system fonts — guarantees Archivo Narrow fallback + return new DefaultFontResolver(fontDirectories: null, searchSystemDirectories: false); + } + + [TestMethod] + public void ResolveFont_UnknownFont_Regular_ShouldFallbackToArchivoNarrow() + { + var resolver = CreateIsolatedResolver(); + var bytes = resolver.ResolveFont(UnknownFont, FontSubFamily.Regular); + + Assert.IsNotNull(bytes, "Should fall back to Archivo Narrow, not return null"); + var font = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", font.NameTable.GetFamilyName()); + Assert.AreEqual(FontSubFamily.Regular, font.NameTable.GetSubfamilyEnum()); + } + + [TestMethod] + public void ResolveFont_UnknownFont_Bold_ShouldFallbackToArchivoNarrowBold() + { + var resolver = CreateIsolatedResolver(); + var bytes = resolver.ResolveFont(UnknownFont, FontSubFamily.Bold); + + Assert.IsNotNull(bytes, "Should fall back to Archivo Narrow Bold, not return null"); + var font = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", font.NameTable.GetFamilyName()); + Assert.AreEqual(FontSubFamily.Bold, font.NameTable.GetSubfamilyEnum()); + } + + [TestMethod] + public void ResolveFont_UnknownFont_Italic_ShouldFallbackToArchivoNarrowItalic() + { + var resolver = CreateIsolatedResolver(); + var bytes = resolver.ResolveFont(UnknownFont, FontSubFamily.Italic); + + Assert.IsNotNull(bytes, "Should fall back to Archivo Narrow Italic, not return null"); + var font = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", font.NameTable.GetFamilyName()); + Assert.AreEqual(FontSubFamily.Italic, font.NameTable.GetSubfamilyEnum()); + } + + [TestMethod] + public void ResolveFont_UnknownFont_BoldItalic_ShouldFallbackToArchivoNarrowBoldItalic() + { + var resolver = CreateIsolatedResolver(); + var bytes = resolver.ResolveFont(UnknownFont, FontSubFamily.BoldItalic); + + Assert.IsNotNull(bytes, "Should fall back to Archivo Narrow Bold Italic, not return null"); + var font = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", font.NameTable.GetFamilyName()); + Assert.AreEqual(FontSubFamily.BoldItalic, font.NameTable.GetSubfamilyEnum()); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/FontProviderTests.cs b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/FontProviderTests.cs new file mode 100644 index 0000000000..b713ae797c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FallbackFonts/FontProviderTests.cs @@ -0,0 +1,428 @@ +/************************************************************************************************* + Font Provider Unit Tests + Tests for automatic emoji fallback functionality and script-based glyph fallback. + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.TextShaping; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.FallbackFonts +{ + [TestClass] + public class FontProviderTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + private OpenTypeFont _robotoFont; + + // U+6F22 = 漢 (a common Han ideograph used in Chinese/Japanese) + private const string HanCharacter = "\u6F22"; + + [TestInitialize] + public void TestSetup() + { + _robotoFont = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + } + + [TestMethod] + public void DefaultFontProvider_EmojiGlyph_ShouldUseFallbackFont() + { + // Arrange + var shaper = new TextShaper(TestFolderEngine, _robotoFont); + + // Act + var shaped = shaper.Shape("😀"); + var usedFonts = shaper.GetUsedFonts().ToList(); + + // Assert + Assert.AreEqual(1, shaped.Glyphs.Length, "Should have 1 glyph"); + Assert.AreNotEqual((ushort)0, shaped.Glyphs[0].GlyphId, "Emoji should not be .notdef"); + Assert.AreNotEqual((byte)0, shaped.Glyphs[0].FontId, "Emoji should come from a fallback font, not primary"); + + // Primary is always registered at FontId 0, even if no glyphs come from it. + // The emoji fallback occupies FontId 1. + Assert.AreEqual(2, usedFonts.Count, "Used fonts should be [primary, emoji fallback]"); + Assert.AreEqual(_robotoFont, usedFonts[0], "Primary font is always FontId 0"); + Assert.AreNotEqual(_robotoFont, usedFonts[1], "Fallback should be the emoji font"); + } + + [TestMethod] + public void DefaultFontProvider_LatinText_ShouldUsePrimaryFont() + { + // Arrange + var shaper = new TextShaper(TestFolderEngine, _robotoFont); + + // Act + var shaped = shaper.Shape("Hello World"); + + // Assert + foreach (var glyph in shaped.Glyphs) + { + Assert.AreEqual((byte)0, glyph.FontId, "All glyphs should be from primary font"); + } + } + + [TestMethod] + public void DefaultFontProvider_MixedTextAndEmoji_ShouldUseMultipleFonts() + { + // Arrange + var shaper = new TextShaper(TestFolderEngine, _robotoFont); + + // Act + var shaped = shaper.Shape("Hello 😀 World"); + var usedFonts = shaper.GetUsedFonts().ToList(); + + // Assert + Assert.AreEqual(2, usedFonts.Count, "Should use 2 fonts (primary + emoji fallback)"); + Assert.AreEqual(_robotoFont, usedFonts[0], "First font should be primary"); + Assert.AreNotEqual(_robotoFont, usedFonts[1], "Second font should be emoji fallback"); + } + + [TestMethod] + public void DefaultFontProvider_DefaultBehavior_DoesNotThrowOnFallback() + { + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Latin, "Archivo Narrow"); + }); + + // Default behaviour: rendering trusts the fallback chain and does not throw, + // even when the requested font resolves only via the embedded fallback. + // (RequireExactFont defaults to false.) + + var shaper = engine.GetTextShaper("Archivo Narrow", FontSubFamily.Regular); + + var shaped = shaper.Shape("Hello There World"); + var usedFonts = shaper.GetUsedFonts().ToList(); + } + + [TestMethod] + public void DefaultFontProvider_EnsureLastFallbackThrowsWhenExactRequired() + { + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Latin, "Archivo Narrow"); + }); + + engine.RequireExactFont = true; + Assert.ThrowsExactly(() => { engine.GetTextShaper("NonExistentFontFamily12345", FontSubFamily.Regular); }); + } + + [TestMethod] + public void TextShaper_SurrogatePair_ShouldMapToSingleGlyph() + { + // Arrange + var shaper = new TextShaper(TestFolderEngine, _robotoFont); + string text = "😀"; // U+1F600 = 2 chars in UTF-16 + + // Act + var shaped = shaper.Shape(text); + + // Assert + Assert.AreEqual(2, text.Length, "Emoji should be 2 chars in .NET"); + Assert.AreEqual(1, shaped.Glyphs.Length, "Should map to 1 glyph"); + Assert.AreEqual((byte)2, shaped.Glyphs[0].CharCount, "Glyph should span 2 chars"); + Assert.AreEqual((ushort)0, shaped.Glyphs[0].ClusterIndex, "Should start at char 0"); + } + + [TestMethod] + public void TextShaper_MultipleEmoji_ShouldMapCorrectly() + { + // Arrange + var shaper = new TextShaper(TestFolderEngine, _robotoFont); + string text = "😀😁😂"; // 3 emoji = 6 chars in UTF-16 + + // Act + var shaped = shaper.Shape(text); + + // Assert + Assert.AreEqual(6, text.Length, "3 emoji = 6 chars"); + Assert.AreEqual(3, shaped.Glyphs.Length, "Should map to 3 glyphs"); + + Assert.AreEqual((ushort)0, shaped.Glyphs[0].ClusterIndex, "First emoji at char 0"); + Assert.AreEqual((byte)2, shaped.Glyphs[0].CharCount, "First emoji spans 2 chars"); + + Assert.AreEqual((ushort)2, shaped.Glyphs[1].ClusterIndex, "Second emoji at char 2"); + Assert.AreEqual((byte)2, shaped.Glyphs[1].CharCount, "Second emoji spans 2 chars"); + + Assert.AreEqual((ushort)4, shaped.Glyphs[2].ClusterIndex, "Third emoji at char 4"); + Assert.AreEqual((byte)2, shaped.Glyphs[2].CharCount, "Third emoji spans 2 chars"); + } + + // ----------------------------------------------------------------------------------------- + // Script-based glyph fallback + // ----------------------------------------------------------------------------------------- + + [TestMethod] + public void DefaultFontProvider_HanGlyphWithConfiguredFallback_RoutesToFallbackFont() + { + // Arrange — explicit script fallback to BIZ UDGothic (which is in the test font folder + // and contains Han glyphs). Use a fresh engine so the default Han chain doesn't + // interfere. + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Han, "BIZ UDGothic"); + }); + + var roboto = engine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(engine, roboto); + + // Act + var shaped = shaper.Shape(HanCharacter); + var usedFonts = shaper.GetUsedFonts().ToList(); + + // Assert — glyph must come from the fallback, not from Roboto's .notdef + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreNotEqual((ushort)0, shaped.Glyphs[0].GlyphId, "Han glyph should not be .notdef"); + Assert.AreNotEqual((byte)0, shaped.Glyphs[0].FontId, "Han glyph should come from a fallback font"); + + Assert.AreEqual(2, usedFonts.Count, "Should use 2 fonts (primary + Han fallback)"); + Assert.AreEqual(roboto, usedFonts[0]); + Assert.AreEqual("BIZ UDGothic", usedFonts[1].NameTable.GetFamilyName()); + } + + [TestMethod] + public void DiagnoseScriptFallback() + { + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Han, "BIZ UDGothic"); + }); + + // Diagnostik 1: vad sätter engine för Han efter konstruktion? + var chain = engine.GetScriptFallback(UnicodeScript.Han); + System.Console.WriteLine($"[DIAG] Han chain: [{string.Join(", ", chain ?? new string[0])}]"); + + // Diagnostik 2: shape och se vad providern returnerar + var roboto = engine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(engine, roboto); + var shaped = shaper.Shape("\u6F22"); + + System.Console.WriteLine($"[DIAG] Glyph count: {shaped.Glyphs.Length}"); + System.Console.WriteLine($"[DIAG] First glyph: GlyphId={shaped.Glyphs[0].GlyphId}, FontId={shaped.Glyphs[0].FontId}"); + + var usedFonts = shaper.GetUsedFonts().ToList(); + System.Console.WriteLine($"[DIAG] Used fonts count: {usedFonts.Count}"); + foreach (var f in usedFonts) + { + System.Console.WriteLine($"[DIAG] - {f.NameTable.GetFamilyName()}"); + } + } + + [TestMethod] + public void DefaultFontProvider_HanGlyphWithNoInstalledFallback_ReturnsNotdef() + { + // Arrange — TestFolderEngine's default Han chain points at Microsoft YaHei, SimSun, etc., + // none of which are present in the test font folder. So a Han character should fall + // through to .notdef. + var roboto = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, roboto); + + // Act + var shaped = shaper.Shape(HanCharacter); + + // Assert + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreEqual((ushort)0, shaped.Glyphs[0].GlyphId, "Glyph should be .notdef"); + Assert.AreEqual((byte)0, shaped.Glyphs[0].FontId, "Provider returns primary font when not found"); + } + + [TestMethod] + public void DefaultFontProvider_EmptyScriptFallbackChain_DisablesFallbackForScript() + { + // Arrange — explicitly disable Han fallback. Even if BIZ UDGothic would have worked + // by default, an empty chain says "do not route Han characters anywhere". + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Han, new string[0]); + }); + + var roboto = engine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(engine, roboto); + + // Act + var shaped = shaper.Shape(HanCharacter); + + // Assert + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreEqual((ushort)0, shaped.Glyphs[0].GlyphId, "Glyph should be .notdef when chain is empty"); + } + + [TestMethod] + public void EpplusFontConfiguration_Reset_RestoresDefaultScriptChains() + { + // Arrange — start with a custom Han chain, then call Reset on the configuration. + // After Reset, the default Han chain (Microsoft YaHei, SimSun, Noto Sans CJK SC, + // PingFang SC) should be reinstated. + // + // We can't directly observe the chain from outside the engine, so we verify the + // behavior indirectly: with the test font folder only and the default chain back + // in place, a Han character should once again be .notdef (none of the default + // chain fonts are in the test folder). + var engine = new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Han, "BIZ UDGothic"); + + // Custom chain was just set above — now undo via Reset. + cfg.Reset(); + + // After Reset we lose the font directories too, so re-add them. + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + }); + + var roboto = engine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(engine, roboto); + + // Act + var shaped = shaper.Shape(HanCharacter); + + // Assert — back to default chain. None of (Microsoft YaHei, SimSun, ...) is in the + // test font folder, so the Han character lands on .notdef. + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreEqual((ushort)0, shaped.Glyphs[0].GlyphId, + "After Reset, the default Han chain should be active again; with no matching fonts installed, glyph is .notdef"); + } + + [TestMethod] + public void DefaultFontProvider_ChineseTextWithPunctuationInAptosNarrow_AllGlyphsResolve() + { + // Reproduces a real-world bug found during PDF export: Chinese text with CJK + // punctuation rendered in Aptos Narrow shows .notdef glyphs for the punctuation + // marks. The Han ideographs route to the Han fallback chain correctly, but the + // fullwidth comma (U+FF0C) and ideographic full stop (U+3002) are classified as + // Unknown by UnicodeScriptClassifier and never reach any fallback font. + // + // After the classifier is fixed to include U+3000-U+303F and U+FF00-U+FFEF in + // the Han range, all 22 glyphs should resolve to non-zero glyph ids. + + // Arrange + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var primary = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, primary); + + string text = "我今天吃了太多饺子,现在我看起来像一个饺子。"; + + // Act + var shaped = shaper.Shape(text); + + // Assert — every glyph in the shaped output must be a real glyph, not .notdef. + // Identify which (if any) failed so the diagnostic message points at the actual + // characters that landed on .notdef. + var notdefs = new System.Collections.Generic.List(); + for (int i = 0; i < shaped.Glyphs.Length; i++) + { + if (shaped.Glyphs[i].GlyphId == 0) + { + int charIndex = shaped.Glyphs[i].ClusterIndex; + char ch = text[charIndex]; + notdefs.Add(string.Format("index {0}: U+{1:X4} '{2}'", charIndex, (int)ch, ch)); + } + } + + Assert.AreEqual(0, notdefs.Count, + "All glyphs should resolve to real glyph ids. The following characters landed on .notdef: " + + string.Join(", ", notdefs)); + } + + // ----------------------------------------------------------------------------------------- + // CJK punctuation routing — reproduces a real-world bug found during PDF export of + // Chinese text rendered with Aptos Narrow. Fullwidth/CJK punctuation should route to the + // Han fallback chain, but currently lands on .notdef because these code-point ranges are + // missing from UnicodeScriptClassifier. + // + // These tests verify the bug first; the classifier fix follows in a separate change. + // ----------------------------------------------------------------------------------------- + + // U+6211 = 我 (Han ideograph) + private const string HanIdeograph = "\u6211"; + + // U+FF0C = , (Fullwidth Comma — used as the CJK comma in Chinese / Japanese / Korean) + private const string CjkFullwidthComma = "\uFF0C"; + + // U+3002 = 。 (Ideographic Full Stop — used as the CJK period) + private const string CjkIdeographicFullStop = "\u3002"; + + [TestMethod] + public void DefaultFontProvider_HanIdeographInAptosNarrow_RoutesToHanFallback() + { + // Arrange — use the system engine because Aptos Narrow is a system font (not in the + // test font folder). Skip the test if Aptos Narrow is not available on this machine. + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var primary = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, primary); + + // Act + var shaped = shaper.Shape(HanIdeograph); + + // Assert — sanity check: a Han ideograph should route to the Han fallback chain. + // If this fails, the entire script routing for Han is broken, not just punctuation. + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreNotEqual((ushort)0, shaped.Glyphs[0].GlyphId, + "Han ideograph should not be .notdef — it should route to the Han fallback chain"); + } + + [TestMethod] + public void DefaultFontProvider_CjkFullwidthCommaInAptosNarrow_RoutesToHanFallback() + { + // Arrange + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var primary = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, primary); + + // Act + var shaped = shaper.Shape(CjkFullwidthComma); + + // Assert — the fullwidth comma is shared CJK punctuation. It should route to the + // Han fallback chain along with the rest of the CJK text it accompanies. Currently + // U+FF00–U+FFEF is missing from UnicodeScriptClassifier, so the comma is classified + // as Unknown and lands on .notdef. + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreNotEqual((ushort)0, shaped.Glyphs[0].GlyphId, + "CJK fullwidth comma (U+FF0C) should not be .notdef — it should route to the Han fallback chain"); + } + + [TestMethod] + public void DefaultFontProvider_CjkIdeographicFullStopInAptosNarrow_RoutesToHanFallback() + { + // Arrange + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var primary = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, primary); + + // Act + var shaped = shaper.Shape(CjkIdeographicFullStop); + + // Assert — the ideographic full stop is shared CJK punctuation. Currently + // U+3000–U+303F is missing from UnicodeScriptClassifier, so the period is + // classified as Unknown and lands on .notdef. + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.AreNotEqual((ushort)0, shaped.Glyphs[0].GlyphId, + "CJK ideographic full stop (U+3002) should not be .notdef — it should route to the Han fallback chain"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FontResolver/DefaultFontResolverTests.cs b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/DefaultFontResolverTests.cs new file mode 100644 index 0000000000..b568398623 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/DefaultFontResolverTests.cs @@ -0,0 +1,312 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/06/2026 EPPlus Software AB DefaultFontResolver unit tests + 05/06/2026 EPPlus Software AB Updated for property-based EpplusFontConfiguration + 05/19/2026 EPPlus Software AB Added case-insensitivity and self-reference tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontResolver; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Reflection; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.FontResolver +{ + /// + /// Unit tests for DefaultFontResolver, covering the four-step resolution flow: + /// 1. Exact match + /// 2. User-configured fallback chain + /// 3. Built-in fallback chain + /// 4. Archivo Narrow (embedded ultimate fallback) + /// + /// Tests use FakeFontScanner and FakeFontFileReader to control exactly which fonts + /// "exist" on the system, making behavior fully deterministic and platform-independent. + /// + [TestClass] + public class DefaultFontResolverTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + #region Step 1 — Exact match + + [TestMethod] + public void ResolveFont_ExactMatchExists_ReturnsExactMatch() + { + // Arrange + var scanner = new FakeFontScanner() + .Register("Calibri", FontSubFamily.Regular, "fake://Calibri.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Calibri.ttf", "FAKE:Calibri"); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + AssertMarker("FAKE:Calibri", bytes); + } + + #endregion + + #region Step 3 — Built-in fallback chain + + [TestMethod] + public void ResolveFont_NoExactMatch_FallsThroughToBuiltinChain() + { + // Arrange — Calibri itself is unavailable, but Carlito (first in built-in chain) is. + var scanner = new FakeFontScanner() + .Register("Carlito", FontSubFamily.Regular, "fake://Carlito.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Carlito.ttf", "FAKE:Carlito"); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + AssertMarker("FAKE:Carlito", bytes); + } + + [TestMethod] + public void ResolveFont_BuiltinChainSkipsMissing_TriesNextEntry() + { + // Arrange — Calibri chain is Carlito → Liberation Sans → Arial → Helvetica. + // Skip the first two and verify Arial is selected. + var scanner = new FakeFontScanner() + .Register("Arial", FontSubFamily.Regular, "fake://Arial.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Arial.ttf", "FAKE:Arial"); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + AssertMarker("FAKE:Arial", bytes); + } + + [TestMethod] + public void ResolveFont_BoldRequest_OnlyMatchesBoldFaces() + { + // Arrange — request Calibri Bold. Carlito Regular is available but Carlito Bold + // is not. The resolver must NOT downgrade to Carlito Regular; it should walk + // further down the chain. + var scanner = new FakeFontScanner() + .Register("Carlito", FontSubFamily.Regular, "fake://Carlito-Regular.ttf") + .Register("Arial", FontSubFamily.Bold, "fake://Arial-Bold.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Carlito-Regular.ttf", "FAKE:CarlitoRegular") + .Register("fake://Arial-Bold.ttf", "FAKE:ArialBold"); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Bold); + + // Assert — must reach Arial Bold, not pick up Carlito Regular along the way + AssertMarker("FAKE:ArialBold", bytes); + } + + #endregion + + #region Step 2 — User-configured fallback chain (precedence) + + [TestMethod] + public void ResolveFont_UserConfigBeforeBuiltin_UserConfigWins() + { + // Arrange — user says "if Calibri is missing, use MyCustomFont". MyCustomFont exists. + // The built-in chain would otherwise pick Carlito (which also exists). Verify the + // user's choice wins. + var config = new EpplusFontConfiguration(); + config.FontFallbacks["Calibri"] = new[] { "MyCustomFont" }; + + var scanner = new FakeFontScanner() + .Register("MyCustomFont", FontSubFamily.Regular, "fake://MyCustomFont.ttf") + .Register("Carlito", FontSubFamily.Regular, "fake://Carlito.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://MyCustomFont.ttf", "FAKE:MyCustomFont") + .Register("fake://Carlito.ttf", "FAKE:Carlito"); + + var resolver = new DefaultFontResolver(config: config, scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + AssertMarker("FAKE:MyCustomFont", bytes); + } + + [TestMethod] + public void ResolveFont_UserConfigMisses_BuiltinTakesOver() + { + // Arrange — user has configured Calibri → NonExistent, but NonExistent isn't on the + // system. Built-in chain Carlito → ... should kick in and find Carlito. + var config = new EpplusFontConfiguration(); + config.FontFallbacks["Calibri"] = new[] { "NonExistent" }; + + var scanner = new FakeFontScanner() + .Register("Carlito", FontSubFamily.Regular, "fake://Carlito.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Carlito.ttf", "FAKE:Carlito"); + + var resolver = new DefaultFontResolver(config: config, scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + AssertMarker("FAKE:Carlito", bytes); + } + + #endregion + + #region Step 4 — Archivo Narrow fallback + + [TestMethod] + public void ResolveFont_NoMatchAnywhere_FallsBackToArchivoNarrow() + { + // Arrange — nothing exists on the system, no user config, no built-in chain entry + // for the requested font (it's a made-up name). + var scanner = new FakeFontScanner(); + var reader = new FakeFontFileReader(); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("DefinitelyNotARealFont_XYZ", FontSubFamily.Regular); + + // Assert — bytes must be a real font (Archivo Narrow), not a fake marker. + // Validate by checking that the bytes parse as a real OpenType font with the + // expected family name. + Assert.IsNotNull(bytes); + Assert.IsTrue(bytes.Length > 1000, "Archivo Narrow should be a real font file, much larger than any fake marker"); + + var parsedFont = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", parsedFont.NameTable.GetFamilyName()); + Assert.AreEqual(FontSubFamily.Regular, parsedFont.NameTable.GetSubfamilyEnum()); + } + + [TestMethod] + public void ResolveFont_BuiltinChainExistsButNothingInstalled_FallsBackToArchivoNarrow() + { + // Arrange — Calibri has a built-in chain but NONE of the chain entries exist on + // the system. Should fall through to Archivo Narrow as ultimate safety net. + var scanner = new FakeFontScanner(); + var reader = new FakeFontFileReader(); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act + var bytes = resolver.ResolveFont("Calibri", FontSubFamily.Regular); + + // Assert + var parsedFont = TestFolderEngine.GetFromBytes(bytes); + Assert.AreEqual("Archivo Narrow", parsedFont.NameTable.GetFamilyName()); + } + + #endregion + + #region GetFontAvailability + + [TestMethod] + public void ResolveFont_ShouldResolveArchivoNarrowBold() + { + var scanner = new FakeFontScanner(); + var reader = new FakeFontFileReader(); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + var availability = resolver.GetFontAvailability("Archivo Narrow", FontSubFamily.Bold); + Assert.AreEqual(FontAvailability.Exact, availability); + } + + #endregion + + #region Built-in chain integrity + + [TestMethod] + public void BuiltinFallbackChains_LookupIsCaseInsensitive() + { + // Arrange — Calibri chain exists in the built-in table. Verify that lookup + // works regardless of how the caller casess the name (CALIBRI, calibri, CaLiBrI). + var scanner = new FakeFontScanner() + .Register("Carlito", FontSubFamily.Regular, "fake://Carlito.ttf"); + var reader = new FakeFontFileReader() + .Register("fake://Carlito.ttf", "FAKE:Carlito"); + + var resolver = new DefaultFontResolver(scanner: scanner, fileReader: reader); + + // Act & Assert — three different casings should all hit the Calibri chain + // and fall through to Carlito. + AssertMarker("FAKE:Carlito", resolver.ResolveFont("CALIBRI", FontSubFamily.Regular)); + AssertMarker("FAKE:Carlito", resolver.ResolveFont("calibri", FontSubFamily.Regular)); + AssertMarker("FAKE:Carlito", resolver.ResolveFont("CaLiBrI", FontSubFamily.Regular)); + } + + [TestMethod] + public void BuiltinFallbackChains_NoEntryReferencesItself() + { + // Arrange — defensive integrity check on the generated table. A self-reference + // (e.g. ["Carlito"] containing "Carlito" in its chain) would be a generator bug + // that wastes lookups and could cause confusing behavior. This test catches any + // such regression at compile/test time. + // + // We use reflection to access the internal BuildChains method so this test + // does not require us to expose the table publicly. + var type = typeof(BuiltinFontFallbackChains); + var buildMethod = type.GetMethod( + "BuildChains", + BindingFlags.NonPublic | BindingFlags.Static); + + Assert.IsNotNull(buildMethod, "BuildChains method should exist on BuiltinFontFallbackChains"); + + var chains = buildMethod.Invoke(null, null) as System.Collections.Generic.Dictionary; + Assert.IsNotNull(chains, "BuildChains should return a non-null dictionary"); + Assert.IsTrue(chains.Count > 0, "Built-in chain table should not be empty"); + + // Act & Assert — verify no entry contains its own key as a fallback target. + foreach (var entry in chains) + { + string key = entry.Key; + foreach (string fallbackName in entry.Value) + { + Assert.IsFalse( + string.Equals(key, fallbackName, StringComparison.OrdinalIgnoreCase), + "Built-in chain for '" + key + "' contains a self-reference. " + + "This is a generator bug — a font cannot fall back to itself."); + } + } + } + + #endregion + + #region Helpers + + /// + /// Asserts that the returned bytes match the UTF-8 encoding of the expected marker. + /// FakeFontFileReader.Register(path, string) writes UTF-8 bytes for the marker, so + /// this is the inverse check. + /// + private static void AssertMarker(string expectedMarker, byte[] actualBytes) + { + Assert.IsNotNull(actualBytes, "ResolveFont returned null"); + var expected = Encoding.UTF8.GetBytes(expectedMarker); + CollectionAssert.AreEqual(expected, actualBytes, + "Expected marker '" + expectedMarker + "' but got " + Encoding.UTF8.GetString(actualBytes)); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontFileReader.cs b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontFileReader.cs new file mode 100644 index 0000000000..c61177b6f4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontFileReader.cs @@ -0,0 +1,62 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/06/2026 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using System; +using System.Collections.Generic; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.FontResolver +{ + /// + /// Test fake of IFontFileReader. Returns predefined bytes for registered file paths. + /// An unregistered path is a test bug — the resolver tried to read a face the scanner + /// returned but the test forgot to register bytes for it — so we throw. + /// + internal sealed class FakeFontFileReader : IFontFileReader + { + private readonly Dictionary _bytesByPath = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Registers explicit bytes for the given file path. Returns this for fluent chaining. + /// + public FakeFontFileReader Register(string filePath, byte[] bytes) + { + _bytesByPath[filePath] = bytes; + return this; + } + + /// + /// Convenience overload: encodes a marker string as UTF-8 bytes and registers them. + /// Useful when the test only cares about identifying which fake was returned, not + /// the exact contents. + /// + public FakeFontFileReader Register(string filePath, string marker) + { + return Register(filePath, Encoding.UTF8.GetBytes(marker)); + } + + public byte[] ReadFontBytes(FontFaceInfo face) + { + if (face == null) + throw new ArgumentNullException("face"); + + if (_bytesByPath.TryGetValue(face.FilePath, out var bytes)) + return bytes; + + throw new InvalidOperationException( + "FakeFontFileReader has no bytes registered for path: " + face.FilePath + + ". Test arrange is incomplete — register bytes for every path the FakeFontScanner returns."); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontScanner.cs b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontScanner.cs new file mode 100644 index 0000000000..7e41519811 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FontResolver/FakeFontScanner.cs @@ -0,0 +1,66 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/06/2026 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tests.FontResolver +{ + /// + /// Test fake of IFontScanner. Returns predefined FontFaceInfo objects for registered + /// (familyName, subFamily) pairs. Lookup is case-insensitive on family name. Unregistered + /// requests return null. + /// + internal sealed class FakeFontScanner : IFontScanner + { + private readonly Dictionary _registry = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Registers that a request for the given family + subfamily should resolve to the + /// given file path. Sets IsExactMatch = true on the returned face. Returns this for + /// fluent chaining. + /// + public FakeFontScanner Register(string familyName, FontSubFamily subFamily, string filePath) + { + _registry[MakeKey(familyName, subFamily)] = new FontFaceInfo + { + FilePath = filePath, + FamilyName = familyName, + Subfamily = subFamily, + IsExactMatch = true, + }; + return this; + } + + public FontFaceInfo? FindBestMatch( + IEnumerable additionalDirectories, + string familyName, + FontSubFamily desiredStyle, + bool searchSystemDirectories) + { + if (string.IsNullOrEmpty(familyName)) + return null; + + return _registry.TryGetValue(MakeKey(familyName, desiredStyle), out var face) + ? face + : null; + } + + private static string MakeKey(string familyName, FontSubFamily subFamily) + { + return familyName + "|" + subFamily; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FontSubsetManagerTests.cs b/src/EPPlus.Fonts.OpenType.Tests/FontSubsetManagerTests.cs new file mode 100644 index 0000000000..2e7289e10f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FontSubsetManagerTests.cs @@ -0,0 +1,133 @@ +using EPPlus.Fonts.OpenType; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests +{ + [TestClass] + public class FontSubsetManagerTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + // Helper: Load a real font for testing + private OpenTypeFont LoadTestFont() + { + // Adjust path to a font available in your test environment + return TestFolderEngine.LoadFont("Roboto"); + } + + [TestMethod] + public void CreateSubsettedProvider_WithAsciiText_ReturnsSubsettedPrimaryFont() + { + // Arrange + var font = LoadTestFont(); + var manager = new FontSubsetManager(TestFolderEngine, font); + + // Act + manager.AddText("Hello World"); + var provider = manager.CreateSubsettedProvider(); + + // Assert - The subset should be a different (smaller) font instance + var subsetFont = provider.PrimaryFont; + Assert.IsNotNull(subsetFont); + Assert.IsTrue(subsetFont.IsSubset, "Primary font should be subsetted"); + + // Verify the subset contains the glyphs we need + foreach (char c in "Hello World") + { + ushort glyphId; + Assert.IsTrue( + subsetFont.CmapTable.TryGetGlyphId(c, out glyphId), + $"Subset should contain glyph for '{c}'"); + Assert.AreNotEqual((ushort)0, glyphId, $"Glyph for '{c}' should not be .notdef"); + } + } + + [TestMethod] + public void CreateSubsettedProvider_WithEmoji_SubsetsFallbackFont() + { + // Arrange + var font = LoadTestFont(); + var provider = new DefaultFontProvider(TestFolderEngine, font); + var manager = new FontSubsetManager(provider); + + // Act - Add text with emoji (U+1F600 = 😀, handled by Noto Emoji fallback) + manager.AddText("Hello 😀"); + var subsettedProvider = manager.CreateSubsettedProvider(); + + // Assert - Should have primary + at least one fallback + var allFonts = subsettedProvider.GetAllFonts().ToList(); + Assert.IsTrue(allFonts.Count >= 2, + "Should have primary font + emoji fallback font"); + + // The fallback font should also be subsetted + var fallbackFont = allFonts[1]; + Assert.IsTrue(fallbackFont.IsSubset, + "Fallback (emoji) font should be subsetted"); + + // The subsetted emoji font should be much smaller than the original + var serialized = fallbackFont.Serialize(); + Assert.IsTrue(serialized.Length < 100 * 1024, + $"Subsetted emoji font should be small, was {serialized.Length / 1024} KB"); + } + + [TestMethod] + public void CreateSubsettedProvider_WithMultipleAddTextCalls_CollectsAllCodePoints() + { + // Arrange + var font = LoadTestFont(); + var manager = new FontSubsetManager(TestFolderEngine, font); + + // Act - Add text in multiple calls (simulates scanning multiple cells) + manager.AddText("ABC"); + manager.AddText("DEF"); + manager.AddText("ADF"); // Overlapping characters + var provider = manager.CreateSubsettedProvider(); + + // Assert - All characters from all calls should be present + var subsetFont = provider.PrimaryFont; + foreach (char c in "ABCDEF") + { + ushort glyphId; + Assert.IsTrue( + subsetFont.CmapTable.TryGetGlyphId(c, out glyphId), + $"Subset should contain glyph for '{c}'"); + } + } + + [TestMethod] + public void CreateSubsettedProvider_UnusedFallbackFontsAreExcluded() + { + // Arrange - DefaultFontProvider has Noto Emoji + Noto Math as fallbacks + var font = LoadTestFont(); + var provider = new DefaultFontProvider(TestFolderEngine, font); + var manager = new FontSubsetManager(provider); + + // Act - Only ASCII text, no emoji or math symbols + manager.AddText("Plain text only"); + var subsettedProvider = manager.CreateSubsettedProvider(); + + // Assert - Should only have the primary font (no fallbacks needed) + var allFonts = subsettedProvider.GetAllFonts().ToList(); + Assert.AreEqual(1, allFonts.Count, + "Only primary font should be included when no fallback glyphs are used"); + } + + [TestMethod] + public void AddText_WithNullOrEmpty_DoesNotThrow() + { + // Arrange + var font = LoadTestFont(); + var manager = new FontSubsetManager(TestFolderEngine, font); + + // Act & Assert - Should handle gracefully + manager.AddText(null); + manager.AddText(""); + manager.AddText("A"); // Then add real text + + var provider = manager.CreateSubsettedProvider(); + Assert.IsNotNull(provider.PrimaryFont); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/FontTestBase.cs b/src/EPPlus.Fonts.OpenType.Tests/FontTestBase.cs new file mode 100644 index 0000000000..2597de6d43 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/FontTestBase.cs @@ -0,0 +1,189 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Test base class + 05/06/2026 EPPlus Software AB Use property-based Configure for font directories + 05/13/2026 EPPlus Software AB Per-engine isolation: expose two engines, remove + global Configure mutations from test infrastructure + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Tests +{ + /// + /// Base class for all font tests. + /// + /// Tests must use one of the exposed engines — TestFolderEngine (no system fonts) or + /// SystemFontsEngine (test folder + system fonts) — instead of the OpenTypeFonts static + /// facade. Going through the facade mutates global state and breaks parallel test execution. + /// + public abstract class FontTestBase + { + /// + /// Test context will be set by MsTest + /// + public abstract TestContext? TestContext { get; set; } + + /// + /// Gets the font folder path (for reading test fonts) + /// + protected static string FontFolder => FontDirectoriesTestHelper.FontFolder; + + /// + /// Gets the list of font folder paths (for reading test fonts) + /// + protected static List FontFolders => FontDirectoriesTestHelper.FontFolders; + + /// + /// Gets whether test output path is available (false in CI/CD) + /// + protected static bool IsTestOutputAvailable => FontDirectoriesTestHelper.IsTestOutputAvailable; + + // ----------------------------------------------------------------------------------------- + // Engines + // ----------------------------------------------------------------------------------------- + + private static readonly Lazy _testFolderEngine = + new Lazy(() => new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + })); + + private static readonly Lazy _systemFontsEngine = + new Lazy(() => new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = true; + })); + + /// + /// Engine configured to search only the test font folder. Use this for tests that + /// can rely on the fonts bundled in the test font folder (BIZUDGothic, CrimsonText, + /// EBGaramond, Mulish, NotoEmoji, NotoSansMath, Oi, OpenSans, PinyonScript, Roboto, + /// SourceSans3, UnicaOne). + /// + protected static OpenTypeFontEngine TestFolderEngine => _testFolderEngine.Value; + + /// + /// Engine configured to search both the test font folder and system directories. + /// Use this only in tests that require fonts not bundled with the test suite + /// (e.g. Aptos Narrow, Goudy Stout, Calibri). Tests using this engine should also + /// use to mark themselves Inconclusive on machines that + /// lack the required system fonts. + /// + protected static OpenTypeFontEngine SystemFontsEngine => _systemFontsEngine.Value; + + /// + /// Asserts that the specified font is available in the given engine with the requested + /// subfamily. If not, the test is marked Inconclusive — useful for tests depending on + /// system-installed fonts that may not be present on every machine. + /// + protected static void RequireFont( + OpenTypeFontEngine engine, + string fontName, + FontSubFamily subFamily = FontSubFamily.Regular) + { + var avail = engine.GetFontAvailability(fontName, subFamily); + if (avail != FontAvailability.Exact) + { + Assert.Inconclusive( + "Test requires " + fontName + " " + subFamily + + " which is not available (availability: " + avail + ")."); + } + } + + // ----------------------------------------------------------------------------------------- + // File output helpers + // ----------------------------------------------------------------------------------------- + + /// + /// Saves a font to the test output folder (c:\epplusTest\Fonts\). + /// Skips silently if running in CI/CD environment. + /// Follows EPPlus pattern: SaveWorkbook(name, pck) + /// + /// Filename (e.g. "subset_Roboto_abc.ttf") + /// Font to save + /// FileInfo for saved file, or null if output not available + protected static FileInfo SaveFont(string fileName, OpenTypeFont font) + { + return FontDirectoriesTestHelper.SaveFontToOutput(font, fileName); + } + + /// + /// Saves a font to the test output folder using the current test name as filename. + /// Automatically appends suffix if provided. + /// Skips silently if running in CI/CD environment. + /// + /// Font to save + /// Optional suffix to append (e.g., "fi", "ff") + /// FileInfo for saved file, or null if output not available + /// + /// SaveFontForCurrentTest(subset); // → "Subset_Ff_ShouldHaveFfLigature.ttf" + /// SaveFontForCurrentTest(subset, "fi"); // → "Subset_CommonLigatures_ShouldWork_fi.ttf" + /// + protected FileInfo? SaveFontForCurrentTest(OpenTypeFont font, string suffix = "") + { + if (!IsTestOutputAvailable) + return null; + + var testName = TestContext?.TestName ?? "UnknownTest"; + var safeSuffix = string.IsNullOrWhiteSpace(suffix) ? "" : $"_{suffix}"; + var fileName = $"{testName}{safeSuffix}.ttf"; + + return FontDirectoriesTestHelper.SaveFontToOutput(font, fileName); + } + + /// + /// Gets a FileInfo for an output file in a subdirectory. + /// Creates subdirectory if needed. + /// Follows EPPlus pattern: GetOutputFile(subPath, fileName) + /// + /// Subdirectory (e.g. "Roboto") + /// Filename (e.g. "subset_abc.ttf") + /// FileInfo or null if output not available + protected static FileInfo GetOutputFile(string subPath, string fileName) + { + return FontDirectoriesTestHelper.GetOutputFile(subPath, fileName); + } + + /// + /// Checks if a font file exists in the output folder + /// + /// Filename to check + /// True if file exists, false if not or output unavailable + protected static bool ExistsOutputFont(string fileName) + { + return FontDirectoriesTestHelper.ExistsOutputFont(fileName); + } + + /// + /// Deletes a font file from the output folder if it exists + /// + /// Filename to delete + protected static void DeleteOutputFont(string fileName) + { + FontDirectoriesTestHelper.DeleteOutputFont(fileName); + } + + // ----------------------------------------------------------------------------------------- + // MSTest lifecycle + // ----------------------------------------------------------------------------------------- + + [ClassInitialize(InheritanceBehavior.BeforeEachDerivedClass)] + public static void BaseClassInitialize(TestContext context) + { + FontDirectoriesTestHelper.ClassInitialize(context); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Bold.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Bold.ttf new file mode 100644 index 0000000000..16be699266 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Bold.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttf new file mode 100644 index 0000000000..030a7c96fd Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttx b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttx new file mode 100644 index 0000000000..dae9240513 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Fonts/BIZUDGothic-Regular.ttx @@ -0,0 +1,4 @@ + + + + diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/CrimsonText-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/CrimsonText-Regular.ttf new file mode 100644 index 0000000000..f24bf2a122 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/CrimsonText-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/EBGaramond-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/EBGaramond-Regular.ttf new file mode 100644 index 0000000000..fd54ab43fd Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/EBGaramond-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Mulish-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Mulish-Regular.ttf new file mode 100644 index 0000000000..acf9664239 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Mulish-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoEmoji-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoEmoji-Regular.ttf new file mode 100644 index 0000000000..b50618f0f5 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoEmoji-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoSansMath-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoSansMath-Regular.ttf new file mode 100644 index 0000000000..7062ca131d Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/NotoSansMath-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Oi-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Oi-Regular.ttf new file mode 100644 index 0000000000..b38dd9df10 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Oi-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000000..8a2c9d9aed Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000000..134d225f66 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-VariableFont_wdth,wght.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000000..9c57fbdb05 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/OpenSans-VariableFont_wdth,wght.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/PinyonScript-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/PinyonScript-Regular.ttf new file mode 100644 index 0000000000..53efff3662 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/PinyonScript-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Bold.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Bold.ttf new file mode 100644 index 0000000000..43da14d84e Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Bold.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-BoldItalic.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-BoldItalic.ttf new file mode 100644 index 0000000000..bcfdab4311 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-BoldItalic.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-ExtraLight.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-ExtraLight.ttf new file mode 100644 index 0000000000..5e517b3baf Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-ExtraLight.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Italic.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Italic.ttf new file mode 100644 index 0000000000..1b5eaa361c Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Italic.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular#1.ttx b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular#1.ttx new file mode 100644 index 0000000000..f9ac1240da --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular#1.ttx @@ -0,0 +1,124057 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ppem: 9 ; + + .notdef: 4 ; + A: 6 ; + AE: 8 ; + AEacute: 8 ; + Aacute: 6 ; + Abreve: 6 ; + Acircumflex: 6 ; + Adieresis: 6 ; + Agrave: 6 ; + Alpha: 6 ; + Alphatonos: 6 ; + Amacron: 6 ; + Aogonek: 6 ; + Aring: 6 ; + Aringacute: 6 ; + Atilde: 6 ; + B: 6 ; + Beta: 6 ; + C: 6 ; + Cacute: 6 ; + Ccaron: 6 ; + Ccedilla: 6 ; + Ccircumflex: 6 ; + Cdotaccent: 6 ; + Chi: 6 ; + D: 6 ; + Dcaron: 6 ; + Dcroat: 6 ; + E: 5 ; + Eacute: 5 ; + Ebreve: 5 ; + Ecaron: 5 ; + Ecircumflex: 5 ; + Edieresis: 5 ; + Edotaccent: 5 ; + Egrave: 5 ; + Emacron: 5 ; + Eng: 6 ; + Eogonek: 5 ; + Epsilon: 5 ; + Epsilontonos: 5 ; + Eta: 6 ; + Etatonos: 6 ; + Eth: 6 ; + Euro: 5 ; + F: 5 ; + G: 6 ; + Gamma: 5 ; + Gbreve: 6 ; + Gcircumflex: 6 ; + Gdotaccent: 6 ; + H: 6 ; + Hbar: 6 ; + Hcircumflex: 6 ; + I: 2 ; + IJ: 7 ; + Iacute: 2 ; + Ibreve: 2 ; + Icircumflex: 2 ; + Idieresis: 2 ; + Idotaccent: 2 ; + Igrave: 2 ; + Imacron: 2 ; + Iogonek: 2 ; + Iota: 2 ; + Iotadieresis: 2 ; + Iotatonos: 2 ; + Itilde: 2 ; + J: 5 ; + Jcircumflex: 5 ; + K: 6 ; + Kappa: 6 ; + L: 5 ; + Lacute: 5 ; + Lambda: 6 ; + Lcaron: 5 ; + Ldot: 5 ; + Lslash: 5 ; + M: 8 ; + Mu: 8 ; + N: 6 ; + Nacute: 6 ; + Ncaron: 6 ; + Ntilde: 6 ; + Nu: 6 ; + O: 6 ; + OE: 9 ; + Oacute: 6 ; + Obreve: 6 ; + Ocircumflex: 6 ; + Odieresis: 6 ; + Ograve: 6 ; + Ohorn: 6 ; + Ohungarumlaut: 6 ; + Omacron: 6 ; + Omegatonos: 6 ; + Omicron: 6 ; + Omicrontonos: 6 ; + Oslash: 6 ; + Oslashacute: 6 ; + Otilde: 6 ; + P: 6 ; + Phi: 6 ; + Pi: 6 ; + Psi: 6 ; + Q: 6 ; + R: 6 ; + Racute: 6 ; + Rcaron: 6 ; + Rho: 6 ; + S: 5 ; + Sacute: 5 ; + Scaron: 5 ; + Scedilla: 5 ; + Scircumflex: 5 ; + Sigma: 5 ; + T: 5 ; + Tau: 5 ; + Tbar: 5 ; + Tcaron: 5 ; + Theta: 6 ; + Thorn: 5 ; + U: 6 ; + Uacute: 6 ; + Ubreve: 6 ; + Ucircumflex: 6 ; + Udieresis: 6 ; + Ugrave: 6 ; + Uhorn: 6 ; + Uhungarumlaut: 6 ; + Umacron: 6 ; + Uogonek: 6 ; + Upsilon: 5 ; + Upsilon1: 5 ; + Upsilondieresis: 5 ; + Upsilontonos: 6 ; + Uring: 6 ; + Utilde: 6 ; + V: 6 ; + W: 8 ; + Wacute: 8 ; + Wcircumflex: 8 ; + Wdieresis: 8 ; + Wgrave: 8 ; + X: 6 ; + Xi: 5 ; + Y: 5 ; + Yacute: 5 ; + Ycircumflex: 5 ; + Ydieresis: 5 ; + Ygrave: 5 ; + Z: 5 ; + Zacute: 5 ; + Zcaron: 5 ; + Zdotaccent: 5 ; + Zeta: 5 ; + a: 5 ; + aacute: 5 ; + abreve: 5 ; + acircumflex: 5 ; + acute: 3 ; + acutecomb: 0 ; + adieresis: 5 ; + ae: 8 ; + aeacute: 8 ; + agrave: 5 ; + alpha: 5 ; + alphatonos: 5 ; + amacron: 5 ; + ampersand: 6 ; + anoteleia: 2 ; + aogonek: 5 ; + approxequal: 5 ; + aring: 5 ; + aringacute: 5 ; + asciicircum: 4 ; + asciitilde: 6 ; + asterisk: 4 ; + at: 8 ; + atilde: 5 ; + b: 5 ; + backslash: 4 ; + bar: 2 ; + beta: 5 ; + braceleft: 3 ; + braceright: 3 ; + bracketleft: 2 ; + bracketright: 2 ; + breve: 4 ; + brokenbar: 2 ; + bullet: 3 ; + c: 5 ; + cacute: 5 ; + caron: 4 ; + ccaron: 5 ; + ccedilla: 5 ; + ccircumflex: 5 ; + cdotaccent: 5 ; + cedilla: 2 ; + cent: 5 ; + chi: 4 ; + circumflex: 4 ; + colon: 2 ; + comma: 2 ; + copyright: 7 ; + currency: 6 ; + d: 5 ; + dagger: 5 ; + daggerdbl: 5 ; + dcaron: 6 ; + dcroat: 5 ; + degree: 3 ; + delta: 5 ; + dieresis: 4 ; + dieresistonos: 5 ; + divide: 5 ; + dollar: 5 ; + dong: 5 ; + dotaccent: 2 ; + dotbelowcomb: 0 ; + dotlessi: 2 ; + e: 5 ; + eacute: 5 ; + ebreve: 5 ; + ecaron: 5 ; + ecircumflex: 5 ; + edieresis: 5 ; + edotaccent: 5 ; + egrave: 5 ; + eight: 5 ; + ellipsis: 6 ; + emacron: 5 ; + emdash: 7 ; + endash: 6 ; + eng: 5 ; + eogonek: 5 ; + epsilon: 5 ; + epsilontonos: 5 ; + equal: 5 ; + estimated: 6 ; + eta: 5 ; + etatonos: 5 ; + eth: 5 ; + exclam: 2 ; + exclamdbl: 5 ; + exclamdown: 2 ; + f: 3 ; + five: 5 ; + fiveeighths: 8 ; + florin: 3 ; + four: 5 ; + fraction: 4 ; + franc: 5 ; + g: 5 ; + gamma: 5 ; + gbreve: 5 ; + gcircumflex: 5 ; + gdotaccent: 5 ; + germandbls: 5 ; + glyph00369: 4 ; + glyph00380: 1 ; + glyph00443: 6 ; + glyph00448: 6 ; + glyph00449: 7 ; + glyph00453: 3 ; + glyph00454: 3 ; + glyph00455: 3 ; + glyph00456: 5 ; + glyph00457: 5 ; + glyph00458: 5 ; + glyph00459: 5 ; + glyph00460: 5 ; + glyph00461: 5 ; + glyph00462: 5 ; + glyph00463: 5 ; + glyph00464: 5 ; + glyph00465: 5 ; + glyph00466: 5 ; + glyph00467: 5 ; + glyph00468: 5 ; + glyph00469: 7 ; + glyph00470: 5 ; + glyph00471: 5 ; + glyph00472: 5 ; + glyph00473: 5 ; + glyph00474: 5 ; + glyph00475: 5 ; + glyph00476: 5 ; + glyph00477: 5 ; + glyph00478: 6 ; + glyph00479: 7 ; + glyph00480: 4 ; + glyph00481: 5 ; + glyph00482: 4 ; + glyph00483: 2 ; + glyph00484: 6 ; + glyph00485: 5 ; + glyph00486: 4 ; + glyph00487: 5 ; + glyph00488: 5 ; + glyph00489: 4 ; + glyph00490: 4 ; + glyph00491: 5 ; + glyph00492: 5 ; + glyph00493: 5 ; + glyph00494: 4 ; + glyph00495: 5 ; + glyph00496: 4 ; + glyph00497: 6 ; + glyph00498: 6 ; + glyph00499: 6 ; + glyph00500: 6 ; + glyph00501: 5 ; + glyph00502: 8 ; + glyph00503: 8 ; + glyph00504: 6 ; + glyph00505: 5 ; + glyph00506: 5 ; + glyph00507: 6 ; + glyph00508: 7 ; + glyph00509: 5 ; + glyph00510: 6 ; + glyph00511: 5 ; + glyph00512: 5 ; + glyph00513: 5 ; + glyph00514: 6 ; + glyph00515: 5 ; + glyph00516: 7 ; + glyph00517: 8 ; + glyph00518: 6 ; + glyph00519: 7 ; + glyph00520: 5 ; + glyph00521: 5 ; + glyph00522: 7 ; + glyph00523: 5 ; + glyph00524: 5 ; + glyph00525: 7 ; + glyph00526: 5 ; + glyph00527: 6 ; + glyph00528: 6 ; + glyph00529: 6 ; + glyph00530: 5 ; + glyph00531: 5 ; + glyph00532: 7 ; + glyph00533: 5 ; + glyph00534: 5 ; + glyph00535: 6 ; + glyph00536: 5 ; + glyph00537: 5 ; + glyph00538: 5 ; + glyph00539: 5 ; + glyph00540: 4 ; + glyph00541: 9 ; + glyph00542: 5 ; + glyph00543: 3 ; + glyph00544: 3 ; + glyph00545: 3 ; + glyph00546: 3 ; + glyph00547: 3 ; + glyph00548: 3 ; + glyph00549: 3 ; + glyph00550: 4 ; + glyph00551: 3 ; + glyph00552: 4 ; + glyph00553: 5 ; + glyph00554: 5 ; + glyph00555: 6 ; + glyph00556: 6 ; + glyph00557: 5 ; + glyph00558: 6 ; + glyph00559: 5 ; + glyph00560: 5 ; + glyph00561: 5 ; + glyph00562: 5 ; + glyph00563: 5 ; + glyph00564: 2 ; + glyph00565: 4 ; + glyph00566: 0 ; + glyph00567: 4 ; + glyph00568: 4 ; + glyph00569: 5 ; + glyph00570: 4 ; + glyph00571: 4 ; + glyph00572: 4 ; + glyph00573: 4 ; + glyph00574: 3 ; + glyph00575: 3 ; + glyph00576: 3 ; + glyph00577: 3 ; + glyph00578: 3 ; + glyph00579: 3 ; + glyph00580: 3 ; + glyph00581: 6 ; + glyph00582: 6 ; + glyph00583: 6 ; + glyph00584: 7 ; + glyph00585: 7 ; + glyph00586: 4 ; + glyph00587: 5 ; + glyph00588: 5 ; + glyph00589: 5 ; + glyph00590: 5 ; + glyph00591: 5 ; + glyph00592: 4 ; + glyph00593: 2 ; + glyph00594: 7 ; + glyph00595: 5 ; + glyph00596: 2 ; + glyph00597: 5 ; + glyph00598: 5 ; + glyph00599: 5 ; + glyph00600: 5 ; + glyph00601: 5 ; + glyph00602: 5 ; + glyph00603: 5 ; + glyph00604: 5 ; + glyph00605: 5 ; + glyph00606: 5 ; + glyph00607: 2 ; + glyph00608: 2 ; + glyph00609: 2 ; + glyph00610: 2 ; + glyph00611: 2 ; + glyph00612: 5 ; + glyph00613: 6 ; + glyph00614: 5 ; + glyph00615: 5 ; + glyph00616: 5 ; + glyph00617: 5 ; + glyph00618: 5 ; + glyph00619: 5 ; + glyph00620: 5 ; + glyph00621: 5 ; + glyph00622: 5 ; + glyph00623: 5 ; + glyph00624: 4 ; + glyph00625: 5 ; + glyph00626: 4 ; + glyph00627: 7 ; + glyph00628: 4 ; + glyph00629: 5 ; + glyph00630: 6 ; + glyph00631: 6 ; + glyph00815: 5 ; + glyph00816: 5 ; + glyph00817: 5 ; + glyph00818: 5 ; + glyph00819: 5 ; + glyph00820: 5 ; + glyph00821: 5 ; + glyph00822: 5 ; + glyph00823: 5 ; + glyph00824: 5 ; + glyph00825: 5 ; + glyph00826: 4 ; + glyph00827: 4 ; + glyph00828: 4 ; + glyph00829: 4 ; + glyph00830: 2 ; + glyph00831: 2 ; + glyph00832: 2 ; + glyph00833: 2 ; + glyph00834: 6 ; + glyph00835: 5 ; + glyph00836: 5 ; + glyph00837: 5 ; + glyph00838: 5 ; + glyph00839: 5 ; + glyph00840: 5 ; + glyph00841: 5 ; + glyph00842: 5 ; + glyph00843: 5 ; + glyph00844: 5 ; + glyph00845: 5 ; + glyph00846: 5 ; + glyph00847: 5 ; + glyph00848: 5 ; + glyph00849: 5 ; + glyph00850: 5 ; + glyph00851: 5 ; + glyph00852: 5 ; + glyph00853: 4 ; + glyph00854: 4 ; + glyph00855: 4 ; + glyph00856: 4 ; + glyph00857: 4 ; + glyph00858: 5 ; + glyph00859: 5 ; + glyph00860: 5 ; + glyph00861: 5 ; + glyph00862: 6 ; + glyph00863: 2 ; + glyph00864: 2 ; + glyph00865: 2 ; + glyph00866: 2 ; + glyph00867: 2 ; + glyph00868: 4 ; + glyph00869: 5 ; + glyph00870: 4 ; + glyph00871: 4 ; + glyph00872: 4 ; + glyph00873: 4 ; + glyph00874: 6 ; + glyph00875: 6 ; + glyph00876: 6 ; + glyph00877: 5 ; + glyph00878: 5 ; + glyph00879: 5 ; + glyph00880: 5 ; + glyph00881: 5 ; + glyph00882: 5 ; + glyph00883: 5 ; + glyph00884: 5 ; + glyph00885: 5 ; + glyph00886: 5 ; + glyph00887: 5 ; + glyph00888: 5 ; + glyph00889: 5 ; + glyph00890: 5 ; + glyph00891: 5 ; + glyph00892: 5 ; + glyph00893: 5 ; + glyph00894: 5 ; + glyph00895: 5 ; + glyph00896: 7 ; + glyph00897: 5 ; + glyph00898: 5 ; + glyph00899: 5 ; + glyph00900: 5 ; + glyph00901: 5 ; + glyph01165: 5 ; + glyph01166: 5 ; + glyph01167: 5 ; + glyph01168: 5 ; + glyph01169: 5 ; + glyph01170: 5 ; + glyph01171: 5 ; + glyph01172: 5 ; + glyph01173: 6 ; + glyph01174: 5 ; + glyph01175: 6 ; + glyph01176: 5 ; + glyph01177: 6 ; + glyph01178: 5 ; + glyph01179: 5 ; + glyph01180: 5 ; + glyph01181: 2 ; + glyph01182: 2 ; + glyph01183: 6 ; + glyph01184: 5 ; + glyph01185: 6 ; + glyph01186: 3 ; + glyph01187: 6 ; + glyph01188: 5 ; + glyph01189: 5 ; + glyph01190: 6 ; + glyph01191: 5 ; + glyph01192: 6 ; + glyph01193: 5 ; + glyph01194: 6 ; + glyph01195: 5 ; + glyph01196: 6 ; + glyph01197: 5 ; + glyph01198: 6 ; + glyph01199: 5 ; + glyph01200: 6 ; + glyph01201: 5 ; + glyph01202: 5 ; + glyph01203: 2 ; + glyph01204: 8 ; + glyph01205: 8 ; + glyph01206: 6 ; + glyph01207: 5 ; + glyph01208: 6 ; + glyph01209: 6 ; + glyph01210: 5 ; + glyph01211: 6 ; + glyph01212: 3 ; + glyph01213: 5 ; + glyph01214: 5 ; + glyph01215: 5 ; + glyph01216: 3 ; + glyph01217: 6 ; + glyph01218: 6 ; + glyph01219: 4 ; + glyph01220: 6 ; + glyph01221: 4 ; + glyph01222: 8 ; + glyph01223: 7 ; + glyph01224: 5 ; + glyph01225: 4 ; + glyph01227: 5 ; + glyph01228: 5 ; + glyph01229: 6 ; + glyph01230: 2 ; + glyph01231: 5 ; + glyph01232: 5 ; + glyph01233: 6 ; + glyph01234: 5 ; + glyph01235: 5 ; + glyph01236: 4 ; + glyph01237: 5 ; + glyph01238: 6 ; + glyph01239: 2 ; + glyph01240: 5 ; + glyph01241: 7 ; + glyph01242: 6 ; + glyph01243: 5 ; + glyph01244: 5 ; + glyph01245: 5 ; + glyph01246: 5 ; + glyph01247: 5 ; + glyph01248: 2 ; + glyph01249: 5 ; + glyph01250: 4 ; + glyph01251: 4 ; + glyph01252: 5 ; + glyph01253: 2 ; + glyph01254: 2 ; + glyph01255: 4 ; + glyph01256: 5 ; + glyph01257: 5 ; + glyph01258: 5 ; + glyph01259: 5 ; + glyph01260: 4 ; + glyph01261: 4 ; + glyph01262: 6 ; + glyph01263: 7 ; + glyph01264: 6 ; + glyph01265: 5 ; + glyph01266: 5 ; + glyph01267: 5 ; + glyph01268: 5 ; + glyph01269: 5 ; + glyph01270: 5 ; + glyph01271: 5 ; + glyph01272: 6 ; + glyph01273: 5 ; + glyph01274: 5 ; + glyph01275: 6 ; + glyph01276: 6 ; + glyph01277: 5 ; + glyph01278: 6 ; + glyph01279: 6 ; + glyph01280: 7 ; + glyph01281: 5 ; + glyph01282: 5 ; + glyph01283: 7 ; + glyph01284: 7 ; + glyph01285: 7 ; + glyph01286: 5 ; + glyph01287: 6 ; + glyph01288: 5 ; + glyph01289: 5 ; + glyph01290: 5 ; + glyph01291: 5 ; + glyph01292: 4 ; + glyph01293: 2 ; + grave: 3 ; + gravecomb: 0 ; + greater: 5 ; + greaterequal: 5 ; + guillemotleft: 4 ; + guillemotright: 4 ; + guilsinglleft: 3 ; + guilsinglright: 3 ; + h: 5 ; + hbar: 5 ; + hcircumflex: 5 ; + hookabovecomb: 0 ; + hungarumlaut: 3 ; + hyphen: 2 ; + i: 2 ; + iacute: 2 ; + ibreve: 2 ; + icircumflex: 2 ; + idieresis: 2 ; + igrave: 2 ; + ij: 4 ; + imacron: 2 ; + infinity: 9 ; + integral: 2 ; + iogonek: 2 ; + iota: 3 ; + iotadieresis: 3 ; + iotadieresistonos: 3 ; + iotatonos: 3 ; + itilde: 2 ; + j: 2 ; + jcircumflex: 2 ; + k: 5 ; + kappa: 5 ; + kgreenlandic: 5 ; + l: 2 ; + lacute: 2 ; + lambda: 5 ; + lcaron: 3 ; + ldot: 3 ; + less: 5 ; + lessequal: 5 ; + lira: 5 ; + logicalnot: 5 ; + longs: 2 ; + lozenge: 5 ; + lslash: 2 ; + m: 8 ; + macron: 4 ; + minus: 5 ; + minute: 2 ; + mu: 5 ; + multiply: 5 ; + n: 5 ; + nacute: 5 ; + napostrophe: 5 ; + ncaron: 5 ; + nine: 5 ; + notequal: 5 ; + ntilde: 5 ; + nu: 4 ; + numbersign: 6 ; + o: 5 ; + oacute: 5 ; + obreve: 5 ; + ocircumflex: 5 ; + odieresis: 5 ; + oe: 8 ; + ogonek: 2 ; + ograve: 5 ; + ohorn: 5 ; + ohungarumlaut: 5 ; + omacron: 5 ; + omega: 7 ; + omega1: 7 ; + omegatonos: 7 ; + omicron: 5 ; + omicrontonos: 5 ; + one: 5 ; + oneeighth: 7 ; + onehalf: 7 ; + onequarter: 7 ; + ordfeminine: 4 ; + ordmasculine: 4 ; + oslash: 5 ; + oslashacute: 5 ; + otilde: 5 ; + p: 5 ; + paragraph: 4 ; + parenleft: 3 ; + parenright: 3 ; + partialdiff: 5 ; + percent: 7 ; + period: 2 ; + periodcentered: 2 ; + perthousand: 9 ; + peseta: 7 ; + phi: 6 ; + pi: 5 ; + plus: 5 ; + plusminus: 5 ; + product: 6 ; + psi: 6 ; + q: 5 ; + question: 4 ; + questiondown: 4 ; + quotedbl: 3 ; + quotedblbase: 3 ; + quotedblleft: 3 ; + quotedblright: 3 ; + quoteleft: 2 ; + quotereversed: 2 ; + quoteright: 2 ; + quotesinglbase: 2 ; + quotesingle: 2 ; + r: 3 ; + racute: 3 ; + radical: 5 ; + rcaron: 3 ; + registered: 7 ; + rho: 5 ; + ring: 3 ; + s: 5 ; + sacute: 5 ; + scaron: 5 ; + scedilla: 5 ; + scircumflex: 5 ; + second: 3 ; + section: 6 ; + semicolon: 2 ; + seven: 5 ; + seveneighths: 7 ; + sigma: 5 ; + sigma1: 5 ; + six: 5 ; + slash: 4 ; + space: 2 ; + sterling: 5 ; + summation: 5 ; + t: 3 ; + tau: 5 ; + tbar: 3 ; + tcaron: 3 ; + theta: 5 ; + theta1: 5 ; + thorn: 5 ; + three: 5 ; + threeeighths: 8 ; + threequarters: 7 ; + tilde: 4 ; + tildecomb: 0 ; + tonos: 2 ; + trademark: 6 ; + two: 5 ; + twodotenleader: 4 ; + u: 5 ; + uacute: 5 ; + ubreve: 5 ; + ucircumflex: 5 ; + udieresis: 5 ; + ugrave: 5 ; + uhorn: 6 ; + uhungarumlaut: 5 ; + umacron: 5 ; + underscore: 4 ; + underscoredbl: 4 ; + uni0000: 0 ; + uni0002: 0 ; + uni000D: 2 ; + uni00A0: 2 ; + uni00AD: 2 ; + uni00B2: 3 ; + uni00B3: 3 ; + uni00B9: 3 ; + uni0122: 6 ; + uni0123: 5 ; + uni0136: 6 ; + uni0137: 5 ; + uni013B: 5 ; + uni013C: 2 ; + uni0145: 6 ; + uni0146: 5 ; + uni0156: 6 ; + uni0157: 3 ; + uni0162: 5 ; + uni0163: 3 ; + uni018F: 6 ; + uni01F0: 2 ; + uni0218: 5 ; + uni0219: 5 ; + uni021A: 5 ; + uni021B: 3 ; + uni0237: 2 ; + uni0259: 5 ; + uni02BC: 2 ; + uni02C9: 4 ; + uni02F3: 3 ; + uni030F: 0 ; + uni0394: 6 ; + uni03A9: 6 ; + uni03BC: 5 ; + uni0400: 5 ; + uni0401: 5 ; + uni0402: 7 ; + uni0403: 5 ; + uni0404: 6 ; + uni0405: 5 ; + uni0406: 2 ; + uni0407: 2 ; + uni0408: 5 ; + uni0409: 10 ; + uni040A: 10 ; + uni040B: 7 ; + uni040C: 6 ; + uni040D: 6 ; + uni040E: 6 ; + uni040F: 6 ; + uni0410: 6 ; + uni0411: 6 ; + uni0412: 6 ; + uni0413: 5 ; + uni0414: 7 ; + uni0415: 5 ; + uni0416: 8 ; + uni0417: 5 ; + uni0418: 6 ; + uni0419: 6 ; + uni041A: 6 ; + uni041B: 6 ; + uni041C: 8 ; + uni041D: 6 ; + uni041E: 6 ; + uni041F: 6 ; + uni0420: 6 ; + uni0421: 6 ; + uni0422: 5 ; + uni0423: 6 ; + uni0424: 7 ; + uni0425: 6 ; + uni0426: 7 ; + uni0427: 6 ; + uni0428: 8 ; + uni0429: 9 ; + uni042A: 7 ; + uni042B: 8 ; + uni042C: 6 ; + uni042D: 6 ; + uni042E: 8 ; + uni042F: 6 ; + uni0430: 5 ; + uni0431: 5 ; + uni0432: 5 ; + uni0433: 4 ; + uni0434: 5 ; + uni0435: 5 ; + uni0436: 7 ; + uni0437: 5 ; + uni0438: 5 ; + uni0439: 5 ; + uni043A: 5 ; + uni043B: 5 ; + uni043C: 7 ; + uni043D: 5 ; + uni043E: 5 ; + uni043F: 5 ; + uni0440: 5 ; + uni0441: 5 ; + uni0442: 4 ; + uni0443: 4 ; + uni0444: 7 ; + uni0445: 4 ; + uni0446: 5 ; + uni0447: 5 ; + uni0448: 7 ; + uni0449: 7 ; + uni044A: 6 ; + uni044B: 7 ; + uni044C: 5 ; + uni044D: 5 ; + uni044E: 7 ; + uni044F: 5 ; + uni0450: 5 ; + uni0451: 5 ; + uni0452: 5 ; + uni0453: 4 ; + uni0454: 5 ; + uni0455: 5 ; + uni0456: 2 ; + uni0457: 2 ; + uni0458: 2 ; + uni0459: 8 ; + uni045A: 8 ; + uni045B: 5 ; + uni045C: 5 ; + uni045D: 5 ; + uni045E: 4 ; + uni045F: 5 ; + uni0460: 8 ; + uni0461: 7 ; + uni0462: 6 ; + uni0463: 5 ; + uni0464: 8 ; + uni0465: 7 ; + uni0466: 5 ; + uni0467: 5 ; + uni0468: 8 ; + uni0469: 7 ; + uni046A: 8 ; + uni046B: 7 ; + uni046C: 10 ; + uni046D: 9 ; + uni046E: 5 ; + uni046F: 4 ; + uni0470: 6 ; + uni0471: 6 ; + uni0472: 6 ; + uni0473: 5 ; + uni0474: 6 ; + uni0475: 5 ; + uni0476: 6 ; + uni0477: 5 ; + uni0478: 10 ; + uni0479: 9 ; + uni047A: 6 ; + uni047B: 5 ; + uni047C: 8 ; + uni047D: 7 ; + uni047E: 8 ; + uni047F: 7 ; + uni0480: 6 ; + uni0481: 5 ; + uni0482: 6 ; + uni0483: 0 ; + uni0484: 0 ; + uni0485: 0 ; + uni0486: 0 ; + uni0488: 0 ; + uni0489: 0 ; + uni048A: 7 ; + uni048B: 6 ; + uni048C: 6 ; + uni048D: 5 ; + uni048E: 6 ; + uni048F: 5 ; + uni0490: 5 ; + uni0491: 4 ; + uni0492: 5 ; + uni0493: 4 ; + uni0494: 5 ; + uni0495: 5 ; + uni0496: 9 ; + uni0497: 7 ; + uni0498: 5 ; + uni0499: 5 ; + uni049A: 6 ; + uni049B: 5 ; + uni049C: 6 ; + uni049D: 5 ; + uni049E: 6 ; + uni049F: 5 ; + uni04A0: 7 ; + uni04A1: 6 ; + uni04A2: 7 ; + uni04A3: 5 ; + uni04A4: 9 ; + uni04A5: 6 ; + uni04A6: 9 ; + uni04A7: 8 ; + uni04A8: 7 ; + uni04A9: 5 ; + uni04AA: 6 ; + uni04AB: 5 ; + uni04AC: 5 ; + uni04AD: 4 ; + uni04AE: 5 ; + uni04AF: 5 ; + uni04B0: 5 ; + uni04B1: 5 ; + uni04B2: 6 ; + uni04B3: 5 ; + uni04B4: 8 ; + uni04B5: 6 ; + uni04B6: 6 ; + uni04B7: 5 ; + uni04B8: 6 ; + uni04B9: 5 ; + uni04BA: 6 ; + uni04BB: 5 ; + uni04BC: 7 ; + uni04BD: 5 ; + uni04BE: 7 ; + uni04BF: 5 ; + uni04C0: 2 ; + uni04C1: 8 ; + uni04C2: 7 ; + uni04C3: 6 ; + uni04C4: 5 ; + uni04C5: 7 ; + uni04C6: 6 ; + uni04C7: 6 ; + uni04C8: 5 ; + uni04C9: 7 ; + uni04CA: 6 ; + uni04CB: 6 ; + uni04CC: 5 ; + uni04CD: 8 ; + uni04CE: 7 ; + uni04CF: 2 ; + uni04D0: 6 ; + uni04D1: 5 ; + uni04D2: 6 ; + uni04D3: 5 ; + uni04D4: 8 ; + uni04D5: 8 ; + uni04D6: 5 ; + uni04D7: 5 ; + uni04D8: 6 ; + uni04D9: 5 ; + uni04DA: 6 ; + uni04DB: 5 ; + uni04DC: 8 ; + uni04DD: 7 ; + uni04DE: 5 ; + uni04DF: 5 ; + uni04E0: 5 ; + uni04E1: 5 ; + uni04E2: 6 ; + uni04E3: 5 ; + uni04E4: 6 ; + uni04E5: 5 ; + uni04E6: 6 ; + uni04E7: 5 ; + uni04E8: 6 ; + uni04E9: 5 ; + uni04EA: 6 ; + uni04EB: 5 ; + uni04EC: 6 ; + uni04ED: 5 ; + uni04EE: 6 ; + uni04EF: 4 ; + uni04F0: 6 ; + uni04F1: 4 ; + uni04F2: 6 ; + uni04F3: 4 ; + uni04F4: 6 ; + uni04F5: 5 ; + uni04F6: 5 ; + uni04F7: 4 ; + uni04F8: 8 ; + uni04F9: 7 ; + uni04FA: 5 ; + uni04FB: 4 ; + uni04FC: 6 ; + uni04FD: 5 ; + uni04FE: 6 ; + uni04FF: 4 ; + uni0500: 6 ; + uni0501: 5 ; + uni0502: 7 ; + uni0503: 8 ; + uni0504: 7 ; + uni0505: 6 ; + uni0506: 5 ; + uni0507: 5 ; + uni0508: 9 ; + uni0509: 7 ; + uni050A: 9 ; + uni050B: 7 ; + uni050C: 6 ; + uni050D: 5 ; + uni050E: 6 ; + uni050F: 6 ; + uni0510: 6 ; + uni0511: 5 ; + uni0512: 7 ; + uni0513: 6 ; + uni1E00: 6 ; + uni1E01: 5 ; + uni1E3E: 8 ; + uni1E3F: 8 ; + uni1EA0: 6 ; + uni1EA1: 5 ; + uni1EA2: 6 ; + uni1EA3: 5 ; + uni1EA4: 6 ; + uni1EA5: 5 ; + uni1EA6: 6 ; + uni1EA7: 5 ; + uni1EA8: 6 ; + uni1EA9: 5 ; + uni1EAA: 6 ; + uni1EAB: 5 ; + uni1EAC: 6 ; + uni1EAD: 5 ; + uni1EAE: 6 ; + uni1EAF: 5 ; + uni1EB0: 6 ; + uni1EB1: 5 ; + uni1EB2: 6 ; + uni1EB3: 5 ; + uni1EB4: 6 ; + uni1EB5: 5 ; + uni1EB6: 6 ; + uni1EB7: 5 ; + uni1EB8: 5 ; + uni1EB9: 5 ; + uni1EBA: 5 ; + uni1EBB: 5 ; + uni1EBC: 5 ; + uni1EBD: 5 ; + uni1EBE: 5 ; + uni1EBF: 5 ; + uni1EC0: 5 ; + uni1EC1: 5 ; + uni1EC2: 5 ; + uni1EC3: 5 ; + uni1EC4: 5 ; + uni1EC5: 5 ; + uni1EC6: 5 ; + uni1EC7: 5 ; + uni1EC8: 2 ; + uni1EC9: 2 ; + uni1ECA: 2 ; + uni1ECB: 2 ; + uni1ECC: 6 ; + uni1ECD: 5 ; + uni1ECE: 6 ; + uni1ECF: 5 ; + uni1ED0: 6 ; + uni1ED1: 5 ; + uni1ED2: 6 ; + uni1ED3: 5 ; + uni1ED4: 6 ; + uni1ED5: 5 ; + uni1ED6: 6 ; + uni1ED7: 5 ; + uni1ED8: 6 ; + uni1ED9: 5 ; + uni1EDA: 6 ; + uni1EDB: 5 ; + uni1EDC: 6 ; + uni1EDD: 5 ; + uni1EDE: 6 ; + uni1EDF: 5 ; + uni1EE0: 6 ; + uni1EE1: 5 ; + uni1EE2: 6 ; + uni1EE3: 5 ; + uni1EE4: 6 ; + uni1EE5: 5 ; + uni1EE6: 6 ; + uni1EE7: 5 ; + uni1EE8: 6 ; + uni1EE9: 6 ; + uni1EEA: 6 ; + uni1EEB: 6 ; + uni1EEC: 6 ; + uni1EED: 6 ; + uni1EEE: 6 ; + uni1EEF: 6 ; + uni1EF0: 6 ; + uni1EF1: 6 ; + uni1EF4: 5 ; + uni1EF5: 4 ; + uni1EF6: 5 ; + uni1EF7: 4 ; + uni1EF8: 5 ; + uni1EF9: 4 ; + uni1F4D: 7 ; + uni2000: 5 ; + uni2001: 9 ; + uni2002: 5 ; + uni2003: 9 ; + uni2004: 3 ; + uni2005: 2 ; + uni2006: 2 ; + uni2007: 5 ; + uni2008: 2 ; + uni2009: 2 ; + uni200A: 1 ; + uni200B: 0 ; + uni2010: 2 ; + uni2011: 2 ; + uni2015: 7 ; + uni2027: 2 ; + uni2074: 3 ; + uni207F: 4 ; + uni20A6: 7 ; + uni20A8: 10 ; + uni20A9: 7 ; + uni20AA: 7 ; + uni20B1: 7 ; + uni20B9: 5 ; + uni20BA: 5 ; + uni20BC: 6 ; + uni20BD: 6 ; + uni2105: 7 ; + uni2113: 4 ; + uni2116: 9 ; + uniEE01: 3 ; + uniEE02: 3 ; + uniF6C3: 2 ; + uniFB01: 5 ; + uniFB02: 5 ; + uniFB03: 8 ; + uniFB04: 8 ; + uniFEFF: 0 ; + uniFFFC: 9 ; + uniFFFD: 9 ; + uogonek: 5 ; + upsilon: 5 ; + upsilondieresis: 5 ; + upsilondieresistonos: 5 ; + upsilontonos: 5 ; + uring: 5 ; + utilde: 5 ; + v: 4 ; + w: 7 ; + wacute: 7 ; + wcircumflex: 7 ; + wdieresis: 7 ; + wgrave: 7 ; + x: 4 ; + xi: 4 ; + y: 4 ; + yacute: 4 ; + ycircumflex: 4 ; + ydieresis: 4 ; + yen: 5 ; + ygrave: 4 ; + z: 4 ; + zacute: 4 ; + zcaron: 4 ; + zdotaccent: 4 ; + zero: 5 ; + zeta: 5 ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 1 value pushed */ + 0 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + PUSHB[ ] /* 1 value pushed */ + 9 + LT[ ] /* LessThan */ + IF[ ] /* If */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + INSTCTRL[ ] /* SetInstrExecControl */ + EIF[ ] /* EndIf */ + PUSHW[ ] /* 1 value pushed */ + 511 + SCANCTRL[ ] /* ScanConversionControl */ + PUSHB[ ] /* 1 value pushed */ + 132 + SCVTCI[ ] /* SetCVTCutIn */ + PUSHB[ ] /* 2 values pushed */ + 9 3 + SDS[ ] /* SetDeltaShiftInGState */ + SDB[ ] /* SetDeltaBaseInGState */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 1 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + ROUND[01] /* Round */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 2 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 1 + LOOPCALL[ ] /* LoopAndCallFunction */ + POP[ ] /* PopTopStack */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 3 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + MD[0] /* MeasureDistance */ + ABS[ ] /* Absolute */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[00] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[00] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + NEG[ ] /* Negate */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + MDAP[1] /* MoveDirectAbsPt */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + ROUND[01] /* Round */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + EQ[ ] /* Equal */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 64 + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + ROUND[01] /* Round */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + EQ[ ] /* Equal */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 64 + NEG[ ] /* Negate */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + MSIRP[0] /* MoveStackIndirRelPt */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 4 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[10] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[10] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + MDAP[1] /* MoveDirectAbsPt */ + MIRP[11101] /* MoveIndirectRelPt */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 5 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + LT[ ] /* LessThan */ + IF[ ] /* If */ + LTEQ[ ] /* LessThenOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 128 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 64 + WCVTP[ ] /* WriteCVTInPixels */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + POP[ ] /* PopTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + PUSHB[ ] /* 1 value pushed */ + 192 + LT[ ] /* LessThan */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 192 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 6 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + ROUND[01] /* Round */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + RDTG[ ] /* RoundDownToGrid */ + ROUND[01] /* Round */ + RTG[ ] /* RoundToGrid */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 7 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 6 + LOOPCALL[ ] /* LoopAndCallFunction */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 8 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 64 + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 0 + EIF[ ] /* EndIf */ + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 128 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 192 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 256 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 320 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + RCVT[ ] /* ReadCVT */ + PUSHW[ ] /* 1 value pushed */ + 384 + LT[ ] /* LessThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 384 + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + RCVT[ ] /* ReadCVT */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + WCVTP[ ] /* WriteCVTInPixels */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 9 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + RCVT[ ] /* ReadCVT */ + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 10 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 40 + RCVT[ ] /* ReadCVT */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 11 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 41 + RCVT[ ] /* ReadCVT */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 12 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + GETINFO[ ] /* GetInfo */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 16384 1024 + MUL[ ] /* Multiply */ + PUSHW[ ] /* 1 value pushed */ + 2048 + GETINFO[ ] /* GetInfo */ + EQ[ ] /* Equal */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 40 1000 + WCVTF[ ] /* WriteCVTInFUnits */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 35 + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + GETINFO[ ] /* GetInfo */ + PUSHW[ ] /* 1 value pushed */ + 4096 + EQ[ ] /* Equal */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 40 1000 + WCVTF[ ] /* WriteCVTInFUnits */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 13 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 64 + GETINFO[ ] /* GetInfo */ + PUSHW[ ] /* 1 value pushed */ + 8192 + AND[ ] /* LogicalAnd */ + IF[ ] /* If */ + PUSHB[ ] /* 2 values pushed */ + 41 0 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + PUSHW[ ] /* 2 values pushed */ + 41 1000 + WCVTP[ ] /* WriteCVTInPixels */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + + + + + + PUSHB[ ] /* 1 value pushed */ + 12 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 0 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 1 16 2 + CALL[ ] /* CallFunction */ + SVTCA[1] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 17 1 2 + CALL[ ] /* CallFunction */ + SVTCA[1] /* SetFPVectorToAxis */ + PUSHB[ ] /* 8 values pushed */ + 17 58 48 37 27 16 0 8 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 8 values pushed */ + 1 72 59 46 33 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 2 88 72 56 40 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 3 82 67 52 37 22 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 4 94 77 60 43 25 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 5 54 44 34 25 15 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 6 113 93 70 50 27 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 7 145 119 92 58 35 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 8 126 103 80 57 26 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 9 84 69 54 38 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 10 118 96 75 54 29 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 11 131 100 78 58 35 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 12 217 178 138 99 60 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 13 20 16 12 9 6 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 14 60 50 39 28 17 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 15 64 52 41 29 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 16 80 65 46 33 20 0 8 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 18 11 7 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 0 + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + RDTG[ ] /* RoundDownToGrid */ + ROUND[01] /* Round */ + RTG[ ] /* RoundToGrid */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 3 values pushed */ + 63 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 95 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 127 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 47 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 79 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 111 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 143 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 175 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 255 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 31 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 63 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 95 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 127 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 15 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 127 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 239 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 31 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 95 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 143 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 207 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 255 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 63 30 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 111 30 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 47 32 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 111 32 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 10 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 12 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 11 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 20 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 22 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 4 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 4 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 14 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 18 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 4 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 35 9 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 31 31 31 47 31 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 30 207 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 30 31 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 63 30 79 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 239 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 207 9 223 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 143 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 20 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 17 values pushed */ + 74 0 90 0 106 0 122 0 138 0 154 0 170 0 186 0 8 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 57 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 5 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 19 values pushed */ + 54 6 70 6 86 6 102 6 118 6 134 6 150 6 166 6 182 6 9 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 12 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 0 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 35 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 20 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 9 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 4 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 38 26 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 4 19 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 134 0 150 0 166 0 182 0 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 137 6 153 6 169 6 185 6 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 5 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 23 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 0 31 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 1 31 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 62 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 12 5 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 12 207 12 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 12 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 58 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 58 207 58 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 47 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 64 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 19 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 21 19 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 42 9 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 34 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 16 42 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 17 9 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 19 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 17 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 31 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 49 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 41 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 46 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 51 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 35 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 1 7 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 50 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 5 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 57 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 64 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 8 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 0 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 7 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 6 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 11 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 17 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 18 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 9 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 3 + CALL[ ] /* CallFunction */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 1 31 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 4 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 5 values pushed */ + 19 6 35 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 1 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 4 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 18 19 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 18 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 7 31 7 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 5 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 39 58 59 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 46 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 54 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 54 46 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 3 31 3 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 10 46 54 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 10 16 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 14 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 17 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 240 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 31 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 31 223 31 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 223 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 95 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 79 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 31 95 31 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 96 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 224 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 224 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 20 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 20 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 19 3 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 4 6 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 13 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 20 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 40 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 47 30 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 26 207 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 39 9 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 26 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 39 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 24 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 42 18 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 42 207 42 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 18 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 34 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 191 34 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 35 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 21 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 16 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 25 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 25 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 6 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 2 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 6 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 34 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 23 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 7 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 19 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 5 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 19 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 35 5 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 77 78 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 71 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 71 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 75 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 75 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 64 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 64 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 44 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 75 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 71 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 64 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 64 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 58 44 64 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 58 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 49 44 64 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 52 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 20 21 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 14 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 5 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 223 42 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 42 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 42 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 25 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 5 8 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 1 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 14 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 175 1 191 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 223 1 239 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 1 47 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 1 127 1 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 37 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 163 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 13 29 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 7 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 12 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 1 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 6 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 7 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 2 112 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 2 112 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 10 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 8 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 2 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 22 112 22 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 22 112 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 18 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 11 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 16 112 16 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 36 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 31 39 47 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 191 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 223 39 239 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 36 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 28 22 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 6 112 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 7 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 27 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 19 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 9 112 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 9 112 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 19 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 7 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 11 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 10 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 23 112 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 23 112 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 7 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 23 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 9 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 17 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 0 112 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 0 112 0 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 2 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 8 112 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 8 112 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 1 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 47 48 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 19 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 33 2 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 12 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 5 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 25 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 25 112 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 25 112 25 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 29 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 29 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 31 1 47 1 63 1 79 1 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 2 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 33 1 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 21 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 16 33 32 33 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 31 18 47 18 63 18 79 18 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 18 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 2 16 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 39 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 32 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 11 31 11 47 11 63 11 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 11 207 11 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 7 values pushed */ + 128 0 144 0 160 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 38 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 11 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 9 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 36 6 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 223 36 239 36 255 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 7 values pushed */ + 15 36 31 36 47 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 36 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 36 31 36 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 23 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 36 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 12 23 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 15 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 2 31 2 47 2 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 63 7 79 7 95 7 111 7 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 63 2 79 2 95 2 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 17 values pushed */ + 15 0 31 0 47 0 63 0 79 0 95 0 111 0 127 0 8 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 223 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 38 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 22 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 8 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 144 14 160 14 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 55 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 55 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 32 8 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 59 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 66 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 23 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 99 6 115 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 51 6 67 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 147 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 23 47 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 223 23 239 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 15 31 15 47 15 63 15 79 15 95 15 111 15 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 112 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 7 31 7 47 7 63 7 79 7 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 25 values pushed */ + 63 23 79 23 95 23 111 23 127 23 143 23 159 23 175 23 191 23 207 23 223 23 239 23 12 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 21 31 21 47 21 63 21 79 21 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 0 31 0 47 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 4 3 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 7 31 7 47 7 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 6 31 6 47 6 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 2 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 10 31 10 47 10 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 5 31 5 47 5 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 14 31 14 47 14 63 14 79 14 95 14 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 7 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 20 14 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 6 31 6 47 6 63 6 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 6 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 63 10 79 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 13 31 13 47 13 63 13 79 13 95 13 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 8 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 15 31 15 47 15 63 15 79 15 95 15 111 15 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 21 31 21 47 21 63 21 79 21 95 21 111 21 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 20 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 27 14 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 63 34 79 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 34 31 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 23 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 17 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 24 23 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 20 31 20 47 20 63 20 79 20 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 223 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 20 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 5 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 31 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 31 25 47 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 8 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 25 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 25 207 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 44 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 42 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 33 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 42 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 19 33 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 30 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 28 0 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 20 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 32 30 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 24 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 34 6 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 12 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 10 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 31 24 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 223 24 239 24 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 31 24 47 24 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 24 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 79 24 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 239 24 255 24 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 24 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 5 values pushed */ + 239 23 255 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 31 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 223 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 111 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 223 23 239 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 31 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 95 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 23 47 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 3 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 176 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 20 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 0 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 223 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 19 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[11100] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 127 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 239 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[11100] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 10 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 25 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 240 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 39 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 39 112 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 39 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 39 112 39 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 29 25 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 7 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 7 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 47 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 21 16 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 7 31 7 47 7 63 7 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 1 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 0 31 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 61 62 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 7 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 21 values pushed */ + 58 0 74 0 90 0 106 0 122 0 138 0 154 0 170 0 186 0 202 0 10 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 21 values pushed */ + 54 6 70 6 86 6 102 6 118 6 134 6 150 6 166 6 182 6 198 6 10 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 6 207 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 31 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 8 47 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 175 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 8 63 8 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 223 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 7 values pushed */ + 95 8 111 8 127 8 3 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 207 8 223 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 8 95 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 96 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 240 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 41 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 21 31 21 47 21 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 4 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 16 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 7 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 9 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 10 9 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 4 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 1 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 7 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 79 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 19 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 2 values pushed */ + 0 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 53 54 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 49 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 49 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + NPUSHB[ ] /* 9 values pushed */ + 15 16 31 16 47 16 63 16 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 4 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 27 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 27 19 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 10 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 38 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 4 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 11 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 27 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 35 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 27 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 11 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 0 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 49 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 53 35 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 55 3 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 82 83 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 36 18 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 38 25 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 43 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 50 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 43 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 64 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 71 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 78 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 33 20 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 14 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 5 values pushed */ + 11 5 27 5 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 27 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 4 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 16 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 9 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 11 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 54 62 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 34 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 34 16 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 53 32 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 53 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 0 53 16 53 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 31 53 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 61 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 63 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 69 70 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 8 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 63 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 22 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 48 35 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 48 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 55 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 55 48 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 20 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 191 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 5 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 15 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 143 14 159 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 14 207 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 239 14 255 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 0 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 8 31 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 3 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 21 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 9 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 1 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 16 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 23 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 8 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 6 8 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 5 2 3 + CALL[ ] /* CallFunction */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 14 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 20 22 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 111 0 127 0 143 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 15 0 31 0 47 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 0 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 14 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 29 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 3 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 0 3 16 3 32 3 48 3 64 3 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 48 9 64 9 80 9 96 9 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 6 31 6 47 6 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 25 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 23 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 22 207 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 22 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 22 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 38 26 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 4 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 20 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 11 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 37 22 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 37 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 37 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 138 4 154 4 170 4 186 4 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 9 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 133 9 149 9 165 9 181 9 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 7 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 21 23 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 28 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 239 8 255 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 8 207 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 15 95 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 143 15 159 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 10 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 18 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 0 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 18 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 1 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 23 207 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 23 175 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 23 63 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 23 127 23 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 16 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 10 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 47 37 63 37 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 37 207 37 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 37 175 37 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 37 127 37 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 6 37 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 34 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 21 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 7 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 7 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 6 207 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 6 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 9 207 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 9 223 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 9 175 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 9 127 9 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 49 50 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 15 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 47 29 63 29 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 29 207 29 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 29 175 29 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 29 127 29 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 3 8 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 20 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 17 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 0 207 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 0 175 0 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 0 63 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 7 values pushed */ + 95 0 111 0 127 0 3 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 3 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 191 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 30 25 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 27 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 27 31 27 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 191 27 207 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 27 175 27 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 27 223 27 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 27 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 27 63 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 27 127 27 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 191 27 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 20 16 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 17 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 191 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 25 16 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 21 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 10 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 2 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 14 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 14 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 38 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 5 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 36 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 28 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 15 207 15 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 63 15 79 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 15 223 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 15 31 15 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 15 175 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 15 63 15 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 15 127 15 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 15 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 28 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 14 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 16 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 23 18 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 20 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 38 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 42 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 42 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 5 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 46 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 43 31 43 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 42 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 46 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 5 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 40 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 40 207 40 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 40 175 40 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 40 127 40 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 43 31 43 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 42 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 22 95 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 12 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 26 207 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 26 175 26 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 26 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 26 63 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 207 26 223 26 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 6 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 5 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 74 75 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 10 13 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 20 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 45 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 47 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 60 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 56 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 68 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 73 74 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 60 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 12 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 19 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 44 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 45 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 59 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 55 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 67 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 67 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 7 10 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 40 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 6 8 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 32 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 69 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 69 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 69 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 76 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 90 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 103 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 63 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 10 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 15 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 12 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 7 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 16 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 16 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 122 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 20 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 21 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 14 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 14 207 14 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 14 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 18 1 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 16 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 18 1 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 6 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 1 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 9 207 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 1 207 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 1 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 1 223 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 1 175 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 1 127 1 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 22 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 23 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 55 56 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 2 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 44 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 51 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 48 49 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 20 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 39 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 10 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 0 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 21 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 23 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 15 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 30 207 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 19 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 19 207 19 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 19 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 2 127 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 239 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 175 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 2 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 2 223 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 2 175 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 2 127 2 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 46 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 16 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 40 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 33 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 14 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 23 40 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 20 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 33 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 14 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 30 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 239 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 95 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 28 127 28 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 28 207 28 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 175 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 28 31 28 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 63 28 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 27 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 7 207 7 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 7 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 7 223 7 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 7 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 7 175 7 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 7 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 7 127 7 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 25 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 11 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 2 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 21 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 36 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 37 11 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 37 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 37 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 38 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 49 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 45 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 69 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 46 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 52 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 50 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 12 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 20 31 20 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 38 23 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 9 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 57 59 60 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 48 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 53 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 57 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 17 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 36 40 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 36 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 0 36 16 36 32 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 29 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 0 29 16 29 32 29 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 33 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 32 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 9 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 17 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 5 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 10 31 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 58 59 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 7 values pushed */ + 42 14 58 14 74 14 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 5 values pushed */ + 54 27 70 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 37 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 43 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 50 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 54 37 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 56 10 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 37 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 32 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 64 4 80 4 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 42 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 41 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 40 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 143 144 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 60 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 62 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 70 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 74 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 80 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 87 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 91 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 97 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 99 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 103 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 109 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 112 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 119 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 123 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 127 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 132 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 136 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 140 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 61 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 70 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 70 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 126 73 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 122 123 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 130 119 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 127 58 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 10 61 70 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 80 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 80 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 111 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 80 111 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 52 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 61 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 60 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 61 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 107 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 103 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 99 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 62 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 60 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 108 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 104 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 100 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 63 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 65 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 70 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 96 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 92 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 88 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 75 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 74 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 90 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 94 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 98 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 71 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 78 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 81 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 118 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 119 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 132 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 122 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 133 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 123 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 136 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 126 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 137 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 127 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 140 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 130 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 141 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 4 values pushed */ + 17 17 16 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 4 values pushed */ + 4 17 28 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 4 values pushed */ + 10 17 23 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 28 30 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 13 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 30 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 18 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 46 47 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 43 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 9 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 14 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 1 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 32 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 2 21 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 0 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + Copyright 2011 Google Inc. All Rights Reserved. + + + Roboto + + + Regular + + + Roboto + + + Roboto + + + Version 2.137; 2017 + + + Roboto-Regular + + + Roboto is a trademark of Google. + + + Google + + + Google.com + + + Christian Robertson + + + Licensed under the Apache License, Version 2.0 + + + http://www.apache.org/licenses/LICENSE-2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000..ddf4bfacb3 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttx b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttx new file mode 100644 index 0000000000..1f6c9d9a63 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Fonts/Roboto-Regular.ttx @@ -0,0 +1,1766 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/SourceSans3-Regular.otf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/SourceSans3-Regular.otf new file mode 100644 index 0000000000..7a261d93d6 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/SourceSans3-Regular.otf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/UnicaOne-Regular.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/UnicaOne-Regular.ttf new file mode 100644 index 0000000000..fa1f1b39ed Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/UnicaOne-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/VariableFonts/ArchivoNarrow-VariableFont_wght.ttf b/src/EPPlus.Fonts.OpenType.Tests/Fonts/VariableFonts/ArchivoNarrow-VariableFont_wght.ttf new file mode 100644 index 0000000000..40f3c644f8 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/Fonts/VariableFonts/ArchivoNarrow-VariableFont_wght.ttf differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Fonts/roboto.ttx b/src/EPPlus.Fonts.OpenType.Tests/Fonts/roboto.ttx new file mode 100644 index 0000000000..f9ac1240da --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Fonts/roboto.ttx @@ -0,0 +1,124057 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ppem: 9 ; + + .notdef: 4 ; + A: 6 ; + AE: 8 ; + AEacute: 8 ; + Aacute: 6 ; + Abreve: 6 ; + Acircumflex: 6 ; + Adieresis: 6 ; + Agrave: 6 ; + Alpha: 6 ; + Alphatonos: 6 ; + Amacron: 6 ; + Aogonek: 6 ; + Aring: 6 ; + Aringacute: 6 ; + Atilde: 6 ; + B: 6 ; + Beta: 6 ; + C: 6 ; + Cacute: 6 ; + Ccaron: 6 ; + Ccedilla: 6 ; + Ccircumflex: 6 ; + Cdotaccent: 6 ; + Chi: 6 ; + D: 6 ; + Dcaron: 6 ; + Dcroat: 6 ; + E: 5 ; + Eacute: 5 ; + Ebreve: 5 ; + Ecaron: 5 ; + Ecircumflex: 5 ; + Edieresis: 5 ; + Edotaccent: 5 ; + Egrave: 5 ; + Emacron: 5 ; + Eng: 6 ; + Eogonek: 5 ; + Epsilon: 5 ; + Epsilontonos: 5 ; + Eta: 6 ; + Etatonos: 6 ; + Eth: 6 ; + Euro: 5 ; + F: 5 ; + G: 6 ; + Gamma: 5 ; + Gbreve: 6 ; + Gcircumflex: 6 ; + Gdotaccent: 6 ; + H: 6 ; + Hbar: 6 ; + Hcircumflex: 6 ; + I: 2 ; + IJ: 7 ; + Iacute: 2 ; + Ibreve: 2 ; + Icircumflex: 2 ; + Idieresis: 2 ; + Idotaccent: 2 ; + Igrave: 2 ; + Imacron: 2 ; + Iogonek: 2 ; + Iota: 2 ; + Iotadieresis: 2 ; + Iotatonos: 2 ; + Itilde: 2 ; + J: 5 ; + Jcircumflex: 5 ; + K: 6 ; + Kappa: 6 ; + L: 5 ; + Lacute: 5 ; + Lambda: 6 ; + Lcaron: 5 ; + Ldot: 5 ; + Lslash: 5 ; + M: 8 ; + Mu: 8 ; + N: 6 ; + Nacute: 6 ; + Ncaron: 6 ; + Ntilde: 6 ; + Nu: 6 ; + O: 6 ; + OE: 9 ; + Oacute: 6 ; + Obreve: 6 ; + Ocircumflex: 6 ; + Odieresis: 6 ; + Ograve: 6 ; + Ohorn: 6 ; + Ohungarumlaut: 6 ; + Omacron: 6 ; + Omegatonos: 6 ; + Omicron: 6 ; + Omicrontonos: 6 ; + Oslash: 6 ; + Oslashacute: 6 ; + Otilde: 6 ; + P: 6 ; + Phi: 6 ; + Pi: 6 ; + Psi: 6 ; + Q: 6 ; + R: 6 ; + Racute: 6 ; + Rcaron: 6 ; + Rho: 6 ; + S: 5 ; + Sacute: 5 ; + Scaron: 5 ; + Scedilla: 5 ; + Scircumflex: 5 ; + Sigma: 5 ; + T: 5 ; + Tau: 5 ; + Tbar: 5 ; + Tcaron: 5 ; + Theta: 6 ; + Thorn: 5 ; + U: 6 ; + Uacute: 6 ; + Ubreve: 6 ; + Ucircumflex: 6 ; + Udieresis: 6 ; + Ugrave: 6 ; + Uhorn: 6 ; + Uhungarumlaut: 6 ; + Umacron: 6 ; + Uogonek: 6 ; + Upsilon: 5 ; + Upsilon1: 5 ; + Upsilondieresis: 5 ; + Upsilontonos: 6 ; + Uring: 6 ; + Utilde: 6 ; + V: 6 ; + W: 8 ; + Wacute: 8 ; + Wcircumflex: 8 ; + Wdieresis: 8 ; + Wgrave: 8 ; + X: 6 ; + Xi: 5 ; + Y: 5 ; + Yacute: 5 ; + Ycircumflex: 5 ; + Ydieresis: 5 ; + Ygrave: 5 ; + Z: 5 ; + Zacute: 5 ; + Zcaron: 5 ; + Zdotaccent: 5 ; + Zeta: 5 ; + a: 5 ; + aacute: 5 ; + abreve: 5 ; + acircumflex: 5 ; + acute: 3 ; + acutecomb: 0 ; + adieresis: 5 ; + ae: 8 ; + aeacute: 8 ; + agrave: 5 ; + alpha: 5 ; + alphatonos: 5 ; + amacron: 5 ; + ampersand: 6 ; + anoteleia: 2 ; + aogonek: 5 ; + approxequal: 5 ; + aring: 5 ; + aringacute: 5 ; + asciicircum: 4 ; + asciitilde: 6 ; + asterisk: 4 ; + at: 8 ; + atilde: 5 ; + b: 5 ; + backslash: 4 ; + bar: 2 ; + beta: 5 ; + braceleft: 3 ; + braceright: 3 ; + bracketleft: 2 ; + bracketright: 2 ; + breve: 4 ; + brokenbar: 2 ; + bullet: 3 ; + c: 5 ; + cacute: 5 ; + caron: 4 ; + ccaron: 5 ; + ccedilla: 5 ; + ccircumflex: 5 ; + cdotaccent: 5 ; + cedilla: 2 ; + cent: 5 ; + chi: 4 ; + circumflex: 4 ; + colon: 2 ; + comma: 2 ; + copyright: 7 ; + currency: 6 ; + d: 5 ; + dagger: 5 ; + daggerdbl: 5 ; + dcaron: 6 ; + dcroat: 5 ; + degree: 3 ; + delta: 5 ; + dieresis: 4 ; + dieresistonos: 5 ; + divide: 5 ; + dollar: 5 ; + dong: 5 ; + dotaccent: 2 ; + dotbelowcomb: 0 ; + dotlessi: 2 ; + e: 5 ; + eacute: 5 ; + ebreve: 5 ; + ecaron: 5 ; + ecircumflex: 5 ; + edieresis: 5 ; + edotaccent: 5 ; + egrave: 5 ; + eight: 5 ; + ellipsis: 6 ; + emacron: 5 ; + emdash: 7 ; + endash: 6 ; + eng: 5 ; + eogonek: 5 ; + epsilon: 5 ; + epsilontonos: 5 ; + equal: 5 ; + estimated: 6 ; + eta: 5 ; + etatonos: 5 ; + eth: 5 ; + exclam: 2 ; + exclamdbl: 5 ; + exclamdown: 2 ; + f: 3 ; + five: 5 ; + fiveeighths: 8 ; + florin: 3 ; + four: 5 ; + fraction: 4 ; + franc: 5 ; + g: 5 ; + gamma: 5 ; + gbreve: 5 ; + gcircumflex: 5 ; + gdotaccent: 5 ; + germandbls: 5 ; + glyph00369: 4 ; + glyph00380: 1 ; + glyph00443: 6 ; + glyph00448: 6 ; + glyph00449: 7 ; + glyph00453: 3 ; + glyph00454: 3 ; + glyph00455: 3 ; + glyph00456: 5 ; + glyph00457: 5 ; + glyph00458: 5 ; + glyph00459: 5 ; + glyph00460: 5 ; + glyph00461: 5 ; + glyph00462: 5 ; + glyph00463: 5 ; + glyph00464: 5 ; + glyph00465: 5 ; + glyph00466: 5 ; + glyph00467: 5 ; + glyph00468: 5 ; + glyph00469: 7 ; + glyph00470: 5 ; + glyph00471: 5 ; + glyph00472: 5 ; + glyph00473: 5 ; + glyph00474: 5 ; + glyph00475: 5 ; + glyph00476: 5 ; + glyph00477: 5 ; + glyph00478: 6 ; + glyph00479: 7 ; + glyph00480: 4 ; + glyph00481: 5 ; + glyph00482: 4 ; + glyph00483: 2 ; + glyph00484: 6 ; + glyph00485: 5 ; + glyph00486: 4 ; + glyph00487: 5 ; + glyph00488: 5 ; + glyph00489: 4 ; + glyph00490: 4 ; + glyph00491: 5 ; + glyph00492: 5 ; + glyph00493: 5 ; + glyph00494: 4 ; + glyph00495: 5 ; + glyph00496: 4 ; + glyph00497: 6 ; + glyph00498: 6 ; + glyph00499: 6 ; + glyph00500: 6 ; + glyph00501: 5 ; + glyph00502: 8 ; + glyph00503: 8 ; + glyph00504: 6 ; + glyph00505: 5 ; + glyph00506: 5 ; + glyph00507: 6 ; + glyph00508: 7 ; + glyph00509: 5 ; + glyph00510: 6 ; + glyph00511: 5 ; + glyph00512: 5 ; + glyph00513: 5 ; + glyph00514: 6 ; + glyph00515: 5 ; + glyph00516: 7 ; + glyph00517: 8 ; + glyph00518: 6 ; + glyph00519: 7 ; + glyph00520: 5 ; + glyph00521: 5 ; + glyph00522: 7 ; + glyph00523: 5 ; + glyph00524: 5 ; + glyph00525: 7 ; + glyph00526: 5 ; + glyph00527: 6 ; + glyph00528: 6 ; + glyph00529: 6 ; + glyph00530: 5 ; + glyph00531: 5 ; + glyph00532: 7 ; + glyph00533: 5 ; + glyph00534: 5 ; + glyph00535: 6 ; + glyph00536: 5 ; + glyph00537: 5 ; + glyph00538: 5 ; + glyph00539: 5 ; + glyph00540: 4 ; + glyph00541: 9 ; + glyph00542: 5 ; + glyph00543: 3 ; + glyph00544: 3 ; + glyph00545: 3 ; + glyph00546: 3 ; + glyph00547: 3 ; + glyph00548: 3 ; + glyph00549: 3 ; + glyph00550: 4 ; + glyph00551: 3 ; + glyph00552: 4 ; + glyph00553: 5 ; + glyph00554: 5 ; + glyph00555: 6 ; + glyph00556: 6 ; + glyph00557: 5 ; + glyph00558: 6 ; + glyph00559: 5 ; + glyph00560: 5 ; + glyph00561: 5 ; + glyph00562: 5 ; + glyph00563: 5 ; + glyph00564: 2 ; + glyph00565: 4 ; + glyph00566: 0 ; + glyph00567: 4 ; + glyph00568: 4 ; + glyph00569: 5 ; + glyph00570: 4 ; + glyph00571: 4 ; + glyph00572: 4 ; + glyph00573: 4 ; + glyph00574: 3 ; + glyph00575: 3 ; + glyph00576: 3 ; + glyph00577: 3 ; + glyph00578: 3 ; + glyph00579: 3 ; + glyph00580: 3 ; + glyph00581: 6 ; + glyph00582: 6 ; + glyph00583: 6 ; + glyph00584: 7 ; + glyph00585: 7 ; + glyph00586: 4 ; + glyph00587: 5 ; + glyph00588: 5 ; + glyph00589: 5 ; + glyph00590: 5 ; + glyph00591: 5 ; + glyph00592: 4 ; + glyph00593: 2 ; + glyph00594: 7 ; + glyph00595: 5 ; + glyph00596: 2 ; + glyph00597: 5 ; + glyph00598: 5 ; + glyph00599: 5 ; + glyph00600: 5 ; + glyph00601: 5 ; + glyph00602: 5 ; + glyph00603: 5 ; + glyph00604: 5 ; + glyph00605: 5 ; + glyph00606: 5 ; + glyph00607: 2 ; + glyph00608: 2 ; + glyph00609: 2 ; + glyph00610: 2 ; + glyph00611: 2 ; + glyph00612: 5 ; + glyph00613: 6 ; + glyph00614: 5 ; + glyph00615: 5 ; + glyph00616: 5 ; + glyph00617: 5 ; + glyph00618: 5 ; + glyph00619: 5 ; + glyph00620: 5 ; + glyph00621: 5 ; + glyph00622: 5 ; + glyph00623: 5 ; + glyph00624: 4 ; + glyph00625: 5 ; + glyph00626: 4 ; + glyph00627: 7 ; + glyph00628: 4 ; + glyph00629: 5 ; + glyph00630: 6 ; + glyph00631: 6 ; + glyph00815: 5 ; + glyph00816: 5 ; + glyph00817: 5 ; + glyph00818: 5 ; + glyph00819: 5 ; + glyph00820: 5 ; + glyph00821: 5 ; + glyph00822: 5 ; + glyph00823: 5 ; + glyph00824: 5 ; + glyph00825: 5 ; + glyph00826: 4 ; + glyph00827: 4 ; + glyph00828: 4 ; + glyph00829: 4 ; + glyph00830: 2 ; + glyph00831: 2 ; + glyph00832: 2 ; + glyph00833: 2 ; + glyph00834: 6 ; + glyph00835: 5 ; + glyph00836: 5 ; + glyph00837: 5 ; + glyph00838: 5 ; + glyph00839: 5 ; + glyph00840: 5 ; + glyph00841: 5 ; + glyph00842: 5 ; + glyph00843: 5 ; + glyph00844: 5 ; + glyph00845: 5 ; + glyph00846: 5 ; + glyph00847: 5 ; + glyph00848: 5 ; + glyph00849: 5 ; + glyph00850: 5 ; + glyph00851: 5 ; + glyph00852: 5 ; + glyph00853: 4 ; + glyph00854: 4 ; + glyph00855: 4 ; + glyph00856: 4 ; + glyph00857: 4 ; + glyph00858: 5 ; + glyph00859: 5 ; + glyph00860: 5 ; + glyph00861: 5 ; + glyph00862: 6 ; + glyph00863: 2 ; + glyph00864: 2 ; + glyph00865: 2 ; + glyph00866: 2 ; + glyph00867: 2 ; + glyph00868: 4 ; + glyph00869: 5 ; + glyph00870: 4 ; + glyph00871: 4 ; + glyph00872: 4 ; + glyph00873: 4 ; + glyph00874: 6 ; + glyph00875: 6 ; + glyph00876: 6 ; + glyph00877: 5 ; + glyph00878: 5 ; + glyph00879: 5 ; + glyph00880: 5 ; + glyph00881: 5 ; + glyph00882: 5 ; + glyph00883: 5 ; + glyph00884: 5 ; + glyph00885: 5 ; + glyph00886: 5 ; + glyph00887: 5 ; + glyph00888: 5 ; + glyph00889: 5 ; + glyph00890: 5 ; + glyph00891: 5 ; + glyph00892: 5 ; + glyph00893: 5 ; + glyph00894: 5 ; + glyph00895: 5 ; + glyph00896: 7 ; + glyph00897: 5 ; + glyph00898: 5 ; + glyph00899: 5 ; + glyph00900: 5 ; + glyph00901: 5 ; + glyph01165: 5 ; + glyph01166: 5 ; + glyph01167: 5 ; + glyph01168: 5 ; + glyph01169: 5 ; + glyph01170: 5 ; + glyph01171: 5 ; + glyph01172: 5 ; + glyph01173: 6 ; + glyph01174: 5 ; + glyph01175: 6 ; + glyph01176: 5 ; + glyph01177: 6 ; + glyph01178: 5 ; + glyph01179: 5 ; + glyph01180: 5 ; + glyph01181: 2 ; + glyph01182: 2 ; + glyph01183: 6 ; + glyph01184: 5 ; + glyph01185: 6 ; + glyph01186: 3 ; + glyph01187: 6 ; + glyph01188: 5 ; + glyph01189: 5 ; + glyph01190: 6 ; + glyph01191: 5 ; + glyph01192: 6 ; + glyph01193: 5 ; + glyph01194: 6 ; + glyph01195: 5 ; + glyph01196: 6 ; + glyph01197: 5 ; + glyph01198: 6 ; + glyph01199: 5 ; + glyph01200: 6 ; + glyph01201: 5 ; + glyph01202: 5 ; + glyph01203: 2 ; + glyph01204: 8 ; + glyph01205: 8 ; + glyph01206: 6 ; + glyph01207: 5 ; + glyph01208: 6 ; + glyph01209: 6 ; + glyph01210: 5 ; + glyph01211: 6 ; + glyph01212: 3 ; + glyph01213: 5 ; + glyph01214: 5 ; + glyph01215: 5 ; + glyph01216: 3 ; + glyph01217: 6 ; + glyph01218: 6 ; + glyph01219: 4 ; + glyph01220: 6 ; + glyph01221: 4 ; + glyph01222: 8 ; + glyph01223: 7 ; + glyph01224: 5 ; + glyph01225: 4 ; + glyph01227: 5 ; + glyph01228: 5 ; + glyph01229: 6 ; + glyph01230: 2 ; + glyph01231: 5 ; + glyph01232: 5 ; + glyph01233: 6 ; + glyph01234: 5 ; + glyph01235: 5 ; + glyph01236: 4 ; + glyph01237: 5 ; + glyph01238: 6 ; + glyph01239: 2 ; + glyph01240: 5 ; + glyph01241: 7 ; + glyph01242: 6 ; + glyph01243: 5 ; + glyph01244: 5 ; + glyph01245: 5 ; + glyph01246: 5 ; + glyph01247: 5 ; + glyph01248: 2 ; + glyph01249: 5 ; + glyph01250: 4 ; + glyph01251: 4 ; + glyph01252: 5 ; + glyph01253: 2 ; + glyph01254: 2 ; + glyph01255: 4 ; + glyph01256: 5 ; + glyph01257: 5 ; + glyph01258: 5 ; + glyph01259: 5 ; + glyph01260: 4 ; + glyph01261: 4 ; + glyph01262: 6 ; + glyph01263: 7 ; + glyph01264: 6 ; + glyph01265: 5 ; + glyph01266: 5 ; + glyph01267: 5 ; + glyph01268: 5 ; + glyph01269: 5 ; + glyph01270: 5 ; + glyph01271: 5 ; + glyph01272: 6 ; + glyph01273: 5 ; + glyph01274: 5 ; + glyph01275: 6 ; + glyph01276: 6 ; + glyph01277: 5 ; + glyph01278: 6 ; + glyph01279: 6 ; + glyph01280: 7 ; + glyph01281: 5 ; + glyph01282: 5 ; + glyph01283: 7 ; + glyph01284: 7 ; + glyph01285: 7 ; + glyph01286: 5 ; + glyph01287: 6 ; + glyph01288: 5 ; + glyph01289: 5 ; + glyph01290: 5 ; + glyph01291: 5 ; + glyph01292: 4 ; + glyph01293: 2 ; + grave: 3 ; + gravecomb: 0 ; + greater: 5 ; + greaterequal: 5 ; + guillemotleft: 4 ; + guillemotright: 4 ; + guilsinglleft: 3 ; + guilsinglright: 3 ; + h: 5 ; + hbar: 5 ; + hcircumflex: 5 ; + hookabovecomb: 0 ; + hungarumlaut: 3 ; + hyphen: 2 ; + i: 2 ; + iacute: 2 ; + ibreve: 2 ; + icircumflex: 2 ; + idieresis: 2 ; + igrave: 2 ; + ij: 4 ; + imacron: 2 ; + infinity: 9 ; + integral: 2 ; + iogonek: 2 ; + iota: 3 ; + iotadieresis: 3 ; + iotadieresistonos: 3 ; + iotatonos: 3 ; + itilde: 2 ; + j: 2 ; + jcircumflex: 2 ; + k: 5 ; + kappa: 5 ; + kgreenlandic: 5 ; + l: 2 ; + lacute: 2 ; + lambda: 5 ; + lcaron: 3 ; + ldot: 3 ; + less: 5 ; + lessequal: 5 ; + lira: 5 ; + logicalnot: 5 ; + longs: 2 ; + lozenge: 5 ; + lslash: 2 ; + m: 8 ; + macron: 4 ; + minus: 5 ; + minute: 2 ; + mu: 5 ; + multiply: 5 ; + n: 5 ; + nacute: 5 ; + napostrophe: 5 ; + ncaron: 5 ; + nine: 5 ; + notequal: 5 ; + ntilde: 5 ; + nu: 4 ; + numbersign: 6 ; + o: 5 ; + oacute: 5 ; + obreve: 5 ; + ocircumflex: 5 ; + odieresis: 5 ; + oe: 8 ; + ogonek: 2 ; + ograve: 5 ; + ohorn: 5 ; + ohungarumlaut: 5 ; + omacron: 5 ; + omega: 7 ; + omega1: 7 ; + omegatonos: 7 ; + omicron: 5 ; + omicrontonos: 5 ; + one: 5 ; + oneeighth: 7 ; + onehalf: 7 ; + onequarter: 7 ; + ordfeminine: 4 ; + ordmasculine: 4 ; + oslash: 5 ; + oslashacute: 5 ; + otilde: 5 ; + p: 5 ; + paragraph: 4 ; + parenleft: 3 ; + parenright: 3 ; + partialdiff: 5 ; + percent: 7 ; + period: 2 ; + periodcentered: 2 ; + perthousand: 9 ; + peseta: 7 ; + phi: 6 ; + pi: 5 ; + plus: 5 ; + plusminus: 5 ; + product: 6 ; + psi: 6 ; + q: 5 ; + question: 4 ; + questiondown: 4 ; + quotedbl: 3 ; + quotedblbase: 3 ; + quotedblleft: 3 ; + quotedblright: 3 ; + quoteleft: 2 ; + quotereversed: 2 ; + quoteright: 2 ; + quotesinglbase: 2 ; + quotesingle: 2 ; + r: 3 ; + racute: 3 ; + radical: 5 ; + rcaron: 3 ; + registered: 7 ; + rho: 5 ; + ring: 3 ; + s: 5 ; + sacute: 5 ; + scaron: 5 ; + scedilla: 5 ; + scircumflex: 5 ; + second: 3 ; + section: 6 ; + semicolon: 2 ; + seven: 5 ; + seveneighths: 7 ; + sigma: 5 ; + sigma1: 5 ; + six: 5 ; + slash: 4 ; + space: 2 ; + sterling: 5 ; + summation: 5 ; + t: 3 ; + tau: 5 ; + tbar: 3 ; + tcaron: 3 ; + theta: 5 ; + theta1: 5 ; + thorn: 5 ; + three: 5 ; + threeeighths: 8 ; + threequarters: 7 ; + tilde: 4 ; + tildecomb: 0 ; + tonos: 2 ; + trademark: 6 ; + two: 5 ; + twodotenleader: 4 ; + u: 5 ; + uacute: 5 ; + ubreve: 5 ; + ucircumflex: 5 ; + udieresis: 5 ; + ugrave: 5 ; + uhorn: 6 ; + uhungarumlaut: 5 ; + umacron: 5 ; + underscore: 4 ; + underscoredbl: 4 ; + uni0000: 0 ; + uni0002: 0 ; + uni000D: 2 ; + uni00A0: 2 ; + uni00AD: 2 ; + uni00B2: 3 ; + uni00B3: 3 ; + uni00B9: 3 ; + uni0122: 6 ; + uni0123: 5 ; + uni0136: 6 ; + uni0137: 5 ; + uni013B: 5 ; + uni013C: 2 ; + uni0145: 6 ; + uni0146: 5 ; + uni0156: 6 ; + uni0157: 3 ; + uni0162: 5 ; + uni0163: 3 ; + uni018F: 6 ; + uni01F0: 2 ; + uni0218: 5 ; + uni0219: 5 ; + uni021A: 5 ; + uni021B: 3 ; + uni0237: 2 ; + uni0259: 5 ; + uni02BC: 2 ; + uni02C9: 4 ; + uni02F3: 3 ; + uni030F: 0 ; + uni0394: 6 ; + uni03A9: 6 ; + uni03BC: 5 ; + uni0400: 5 ; + uni0401: 5 ; + uni0402: 7 ; + uni0403: 5 ; + uni0404: 6 ; + uni0405: 5 ; + uni0406: 2 ; + uni0407: 2 ; + uni0408: 5 ; + uni0409: 10 ; + uni040A: 10 ; + uni040B: 7 ; + uni040C: 6 ; + uni040D: 6 ; + uni040E: 6 ; + uni040F: 6 ; + uni0410: 6 ; + uni0411: 6 ; + uni0412: 6 ; + uni0413: 5 ; + uni0414: 7 ; + uni0415: 5 ; + uni0416: 8 ; + uni0417: 5 ; + uni0418: 6 ; + uni0419: 6 ; + uni041A: 6 ; + uni041B: 6 ; + uni041C: 8 ; + uni041D: 6 ; + uni041E: 6 ; + uni041F: 6 ; + uni0420: 6 ; + uni0421: 6 ; + uni0422: 5 ; + uni0423: 6 ; + uni0424: 7 ; + uni0425: 6 ; + uni0426: 7 ; + uni0427: 6 ; + uni0428: 8 ; + uni0429: 9 ; + uni042A: 7 ; + uni042B: 8 ; + uni042C: 6 ; + uni042D: 6 ; + uni042E: 8 ; + uni042F: 6 ; + uni0430: 5 ; + uni0431: 5 ; + uni0432: 5 ; + uni0433: 4 ; + uni0434: 5 ; + uni0435: 5 ; + uni0436: 7 ; + uni0437: 5 ; + uni0438: 5 ; + uni0439: 5 ; + uni043A: 5 ; + uni043B: 5 ; + uni043C: 7 ; + uni043D: 5 ; + uni043E: 5 ; + uni043F: 5 ; + uni0440: 5 ; + uni0441: 5 ; + uni0442: 4 ; + uni0443: 4 ; + uni0444: 7 ; + uni0445: 4 ; + uni0446: 5 ; + uni0447: 5 ; + uni0448: 7 ; + uni0449: 7 ; + uni044A: 6 ; + uni044B: 7 ; + uni044C: 5 ; + uni044D: 5 ; + uni044E: 7 ; + uni044F: 5 ; + uni0450: 5 ; + uni0451: 5 ; + uni0452: 5 ; + uni0453: 4 ; + uni0454: 5 ; + uni0455: 5 ; + uni0456: 2 ; + uni0457: 2 ; + uni0458: 2 ; + uni0459: 8 ; + uni045A: 8 ; + uni045B: 5 ; + uni045C: 5 ; + uni045D: 5 ; + uni045E: 4 ; + uni045F: 5 ; + uni0460: 8 ; + uni0461: 7 ; + uni0462: 6 ; + uni0463: 5 ; + uni0464: 8 ; + uni0465: 7 ; + uni0466: 5 ; + uni0467: 5 ; + uni0468: 8 ; + uni0469: 7 ; + uni046A: 8 ; + uni046B: 7 ; + uni046C: 10 ; + uni046D: 9 ; + uni046E: 5 ; + uni046F: 4 ; + uni0470: 6 ; + uni0471: 6 ; + uni0472: 6 ; + uni0473: 5 ; + uni0474: 6 ; + uni0475: 5 ; + uni0476: 6 ; + uni0477: 5 ; + uni0478: 10 ; + uni0479: 9 ; + uni047A: 6 ; + uni047B: 5 ; + uni047C: 8 ; + uni047D: 7 ; + uni047E: 8 ; + uni047F: 7 ; + uni0480: 6 ; + uni0481: 5 ; + uni0482: 6 ; + uni0483: 0 ; + uni0484: 0 ; + uni0485: 0 ; + uni0486: 0 ; + uni0488: 0 ; + uni0489: 0 ; + uni048A: 7 ; + uni048B: 6 ; + uni048C: 6 ; + uni048D: 5 ; + uni048E: 6 ; + uni048F: 5 ; + uni0490: 5 ; + uni0491: 4 ; + uni0492: 5 ; + uni0493: 4 ; + uni0494: 5 ; + uni0495: 5 ; + uni0496: 9 ; + uni0497: 7 ; + uni0498: 5 ; + uni0499: 5 ; + uni049A: 6 ; + uni049B: 5 ; + uni049C: 6 ; + uni049D: 5 ; + uni049E: 6 ; + uni049F: 5 ; + uni04A0: 7 ; + uni04A1: 6 ; + uni04A2: 7 ; + uni04A3: 5 ; + uni04A4: 9 ; + uni04A5: 6 ; + uni04A6: 9 ; + uni04A7: 8 ; + uni04A8: 7 ; + uni04A9: 5 ; + uni04AA: 6 ; + uni04AB: 5 ; + uni04AC: 5 ; + uni04AD: 4 ; + uni04AE: 5 ; + uni04AF: 5 ; + uni04B0: 5 ; + uni04B1: 5 ; + uni04B2: 6 ; + uni04B3: 5 ; + uni04B4: 8 ; + uni04B5: 6 ; + uni04B6: 6 ; + uni04B7: 5 ; + uni04B8: 6 ; + uni04B9: 5 ; + uni04BA: 6 ; + uni04BB: 5 ; + uni04BC: 7 ; + uni04BD: 5 ; + uni04BE: 7 ; + uni04BF: 5 ; + uni04C0: 2 ; + uni04C1: 8 ; + uni04C2: 7 ; + uni04C3: 6 ; + uni04C4: 5 ; + uni04C5: 7 ; + uni04C6: 6 ; + uni04C7: 6 ; + uni04C8: 5 ; + uni04C9: 7 ; + uni04CA: 6 ; + uni04CB: 6 ; + uni04CC: 5 ; + uni04CD: 8 ; + uni04CE: 7 ; + uni04CF: 2 ; + uni04D0: 6 ; + uni04D1: 5 ; + uni04D2: 6 ; + uni04D3: 5 ; + uni04D4: 8 ; + uni04D5: 8 ; + uni04D6: 5 ; + uni04D7: 5 ; + uni04D8: 6 ; + uni04D9: 5 ; + uni04DA: 6 ; + uni04DB: 5 ; + uni04DC: 8 ; + uni04DD: 7 ; + uni04DE: 5 ; + uni04DF: 5 ; + uni04E0: 5 ; + uni04E1: 5 ; + uni04E2: 6 ; + uni04E3: 5 ; + uni04E4: 6 ; + uni04E5: 5 ; + uni04E6: 6 ; + uni04E7: 5 ; + uni04E8: 6 ; + uni04E9: 5 ; + uni04EA: 6 ; + uni04EB: 5 ; + uni04EC: 6 ; + uni04ED: 5 ; + uni04EE: 6 ; + uni04EF: 4 ; + uni04F0: 6 ; + uni04F1: 4 ; + uni04F2: 6 ; + uni04F3: 4 ; + uni04F4: 6 ; + uni04F5: 5 ; + uni04F6: 5 ; + uni04F7: 4 ; + uni04F8: 8 ; + uni04F9: 7 ; + uni04FA: 5 ; + uni04FB: 4 ; + uni04FC: 6 ; + uni04FD: 5 ; + uni04FE: 6 ; + uni04FF: 4 ; + uni0500: 6 ; + uni0501: 5 ; + uni0502: 7 ; + uni0503: 8 ; + uni0504: 7 ; + uni0505: 6 ; + uni0506: 5 ; + uni0507: 5 ; + uni0508: 9 ; + uni0509: 7 ; + uni050A: 9 ; + uni050B: 7 ; + uni050C: 6 ; + uni050D: 5 ; + uni050E: 6 ; + uni050F: 6 ; + uni0510: 6 ; + uni0511: 5 ; + uni0512: 7 ; + uni0513: 6 ; + uni1E00: 6 ; + uni1E01: 5 ; + uni1E3E: 8 ; + uni1E3F: 8 ; + uni1EA0: 6 ; + uni1EA1: 5 ; + uni1EA2: 6 ; + uni1EA3: 5 ; + uni1EA4: 6 ; + uni1EA5: 5 ; + uni1EA6: 6 ; + uni1EA7: 5 ; + uni1EA8: 6 ; + uni1EA9: 5 ; + uni1EAA: 6 ; + uni1EAB: 5 ; + uni1EAC: 6 ; + uni1EAD: 5 ; + uni1EAE: 6 ; + uni1EAF: 5 ; + uni1EB0: 6 ; + uni1EB1: 5 ; + uni1EB2: 6 ; + uni1EB3: 5 ; + uni1EB4: 6 ; + uni1EB5: 5 ; + uni1EB6: 6 ; + uni1EB7: 5 ; + uni1EB8: 5 ; + uni1EB9: 5 ; + uni1EBA: 5 ; + uni1EBB: 5 ; + uni1EBC: 5 ; + uni1EBD: 5 ; + uni1EBE: 5 ; + uni1EBF: 5 ; + uni1EC0: 5 ; + uni1EC1: 5 ; + uni1EC2: 5 ; + uni1EC3: 5 ; + uni1EC4: 5 ; + uni1EC5: 5 ; + uni1EC6: 5 ; + uni1EC7: 5 ; + uni1EC8: 2 ; + uni1EC9: 2 ; + uni1ECA: 2 ; + uni1ECB: 2 ; + uni1ECC: 6 ; + uni1ECD: 5 ; + uni1ECE: 6 ; + uni1ECF: 5 ; + uni1ED0: 6 ; + uni1ED1: 5 ; + uni1ED2: 6 ; + uni1ED3: 5 ; + uni1ED4: 6 ; + uni1ED5: 5 ; + uni1ED6: 6 ; + uni1ED7: 5 ; + uni1ED8: 6 ; + uni1ED9: 5 ; + uni1EDA: 6 ; + uni1EDB: 5 ; + uni1EDC: 6 ; + uni1EDD: 5 ; + uni1EDE: 6 ; + uni1EDF: 5 ; + uni1EE0: 6 ; + uni1EE1: 5 ; + uni1EE2: 6 ; + uni1EE3: 5 ; + uni1EE4: 6 ; + uni1EE5: 5 ; + uni1EE6: 6 ; + uni1EE7: 5 ; + uni1EE8: 6 ; + uni1EE9: 6 ; + uni1EEA: 6 ; + uni1EEB: 6 ; + uni1EEC: 6 ; + uni1EED: 6 ; + uni1EEE: 6 ; + uni1EEF: 6 ; + uni1EF0: 6 ; + uni1EF1: 6 ; + uni1EF4: 5 ; + uni1EF5: 4 ; + uni1EF6: 5 ; + uni1EF7: 4 ; + uni1EF8: 5 ; + uni1EF9: 4 ; + uni1F4D: 7 ; + uni2000: 5 ; + uni2001: 9 ; + uni2002: 5 ; + uni2003: 9 ; + uni2004: 3 ; + uni2005: 2 ; + uni2006: 2 ; + uni2007: 5 ; + uni2008: 2 ; + uni2009: 2 ; + uni200A: 1 ; + uni200B: 0 ; + uni2010: 2 ; + uni2011: 2 ; + uni2015: 7 ; + uni2027: 2 ; + uni2074: 3 ; + uni207F: 4 ; + uni20A6: 7 ; + uni20A8: 10 ; + uni20A9: 7 ; + uni20AA: 7 ; + uni20B1: 7 ; + uni20B9: 5 ; + uni20BA: 5 ; + uni20BC: 6 ; + uni20BD: 6 ; + uni2105: 7 ; + uni2113: 4 ; + uni2116: 9 ; + uniEE01: 3 ; + uniEE02: 3 ; + uniF6C3: 2 ; + uniFB01: 5 ; + uniFB02: 5 ; + uniFB03: 8 ; + uniFB04: 8 ; + uniFEFF: 0 ; + uniFFFC: 9 ; + uniFFFD: 9 ; + uogonek: 5 ; + upsilon: 5 ; + upsilondieresis: 5 ; + upsilondieresistonos: 5 ; + upsilontonos: 5 ; + uring: 5 ; + utilde: 5 ; + v: 4 ; + w: 7 ; + wacute: 7 ; + wcircumflex: 7 ; + wdieresis: 7 ; + wgrave: 7 ; + x: 4 ; + xi: 4 ; + y: 4 ; + yacute: 4 ; + ycircumflex: 4 ; + ydieresis: 4 ; + yen: 5 ; + ygrave: 4 ; + z: 4 ; + zacute: 4 ; + zcaron: 4 ; + zdotaccent: 4 ; + zero: 5 ; + zeta: 5 ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 1 value pushed */ + 0 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + PUSHB[ ] /* 1 value pushed */ + 9 + LT[ ] /* LessThan */ + IF[ ] /* If */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + INSTCTRL[ ] /* SetInstrExecControl */ + EIF[ ] /* EndIf */ + PUSHW[ ] /* 1 value pushed */ + 511 + SCANCTRL[ ] /* ScanConversionControl */ + PUSHB[ ] /* 1 value pushed */ + 132 + SCVTCI[ ] /* SetCVTCutIn */ + PUSHB[ ] /* 2 values pushed */ + 9 3 + SDS[ ] /* SetDeltaShiftInGState */ + SDB[ ] /* SetDeltaBaseInGState */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 1 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + ROUND[01] /* Round */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 2 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 1 + LOOPCALL[ ] /* LoopAndCallFunction */ + POP[ ] /* PopTopStack */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 3 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + MD[0] /* MeasureDistance */ + ABS[ ] /* Absolute */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[00] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[00] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + NEG[ ] /* Negate */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + MDAP[1] /* MoveDirectAbsPt */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + ROUND[01] /* Round */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + EQ[ ] /* Equal */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 64 + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + ROUND[01] /* Round */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 0 + EQ[ ] /* Equal */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 64 + NEG[ ] /* Negate */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + MSIRP[0] /* MoveStackIndirRelPt */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 4 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[10] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + PUSHB[ ] /* 1 value pushed */ + 4 + CINDEX[ ] /* CopyXToTopStack */ + GC[0] /* GetCoordOnPVector */ + DUP[ ] /* DuplicateTopStack */ + ROUND[10] /* Round */ + SUB[ ] /* Subtract */ + ABS[ ] /* Absolute */ + GT[ ] /* GreaterThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + ROLL[ ] /* RollTopThreeStack */ + EIF[ ] /* EndIf */ + MDAP[1] /* MoveDirectAbsPt */ + MIRP[11101] /* MoveIndirectRelPt */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 5 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + LT[ ] /* LessThan */ + IF[ ] /* If */ + LTEQ[ ] /* LessThenOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 128 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 64 + WCVTP[ ] /* WriteCVTInPixels */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + POP[ ] /* PopTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + PUSHB[ ] /* 1 value pushed */ + 192 + LT[ ] /* LessThan */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 192 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 6 + FDEF[ ] /* FunctionDefinition */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + ROUND[01] /* Round */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + DUP[ ] /* DuplicateTopStack */ + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + RDTG[ ] /* RoundDownToGrid */ + ROUND[01] /* Round */ + RTG[ ] /* RoundToGrid */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 1 value pushed */ + 1 + ADD[ ] /* Add */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 7 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 6 + LOOPCALL[ ] /* LoopAndCallFunction */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 8 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 64 + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 0 + EIF[ ] /* EndIf */ + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 128 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHB[ ] /* 1 value pushed */ + 192 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 256 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 320 + ROLL[ ] /* RollTopThreeStack */ + ROLL[ ] /* RollTopThreeStack */ + ELSE[ ] /* Else */ + ROLL[ ] /* RollTopThreeStack */ + SWAP[ ] /* SwapTopStack */ + EIF[ ] /* EndIf */ + DUP[ ] /* DuplicateTopStack */ + PUSHB[ ] /* 1 value pushed */ + 3 + MINDEX[ ] /* MoveXToTopStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + RCVT[ ] /* ReadCVT */ + PUSHW[ ] /* 1 value pushed */ + 384 + LT[ ] /* LessThan */ + IF[ ] /* If */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + PUSHW[ ] /* 1 value pushed */ + 384 + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 3 + CINDEX[ ] /* CopyXToTopStack */ + RCVT[ ] /* ReadCVT */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + SWAP[ ] /* SwapTopStack */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + WCVTP[ ] /* WriteCVTInPixels */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 9 + FDEF[ ] /* FunctionDefinition */ + MPPEM[ ] /* MeasurePixelPerEm */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + RCVT[ ] /* ReadCVT */ + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + POP[ ] /* PopTopStack */ + POP[ ] /* PopTopStack */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 10 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 40 + RCVT[ ] /* ReadCVT */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 11 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 41 + RCVT[ ] /* ReadCVT */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 12 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + GETINFO[ ] /* GetInfo */ + DUP[ ] /* DuplicateTopStack */ + ROLL[ ] /* RollTopThreeStack */ + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 16384 1024 + MUL[ ] /* Multiply */ + PUSHW[ ] /* 1 value pushed */ + 2048 + GETINFO[ ] /* GetInfo */ + EQ[ ] /* Equal */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 40 1000 + WCVTF[ ] /* WriteCVTInFUnits */ + EIF[ ] /* EndIf */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 1 value pushed */ + 35 + GTEQ[ ] /* GreaterThanOrEqual */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + GETINFO[ ] /* GetInfo */ + PUSHW[ ] /* 1 value pushed */ + 4096 + EQ[ ] /* Equal */ + IF[ ] /* If */ + PUSHW[ ] /* 2 values pushed */ + 40 1000 + WCVTF[ ] /* WriteCVTInFUnits */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 13 + FDEF[ ] /* FunctionDefinition */ + PUSHB[ ] /* 1 value pushed */ + 64 + GETINFO[ ] /* GetInfo */ + PUSHW[ ] /* 1 value pushed */ + 8192 + AND[ ] /* LogicalAnd */ + IF[ ] /* If */ + PUSHB[ ] /* 2 values pushed */ + 41 0 + WCVTP[ ] /* WriteCVTInPixels */ + ELSE[ ] /* Else */ + PUSHW[ ] /* 2 values pushed */ + 41 1000 + WCVTP[ ] /* WriteCVTInPixels */ + EIF[ ] /* EndIf */ + ENDF[ ] /* EndFunctionDefinition */ + + + + + + PUSHB[ ] /* 1 value pushed */ + 12 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 0 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 1 16 2 + CALL[ ] /* CallFunction */ + SVTCA[1] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 17 1 2 + CALL[ ] /* CallFunction */ + SVTCA[1] /* SetFPVectorToAxis */ + PUSHB[ ] /* 8 values pushed */ + 17 58 48 37 27 16 0 8 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 8 values pushed */ + 1 72 59 46 33 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 2 88 72 56 40 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 3 82 67 52 37 22 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 4 94 77 60 43 25 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 5 54 44 34 25 15 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 6 113 93 70 50 27 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 7 145 119 92 58 35 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 8 126 103 80 57 26 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 9 84 69 54 38 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 10 118 96 75 54 29 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 11 131 100 78 58 35 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 12 217 178 138 99 60 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 13 20 16 12 9 6 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 14 60 50 39 28 17 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 15 64 52 41 29 20 0 8 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 8 values pushed */ + 16 80 65 46 33 20 0 8 + CALL[ ] /* CallFunction */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 18 11 7 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 0 + DUP[ ] /* DuplicateTopStack */ + RCVT[ ] /* ReadCVT */ + RDTG[ ] /* RoundDownToGrid */ + ROUND[01] /* Round */ + RTG[ ] /* RoundToGrid */ + WCVTP[ ] /* WriteCVTInPixels */ + PUSHB[ ] /* 3 values pushed */ + 63 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 95 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 127 26 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 47 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 79 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 111 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 143 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 175 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 255 26 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 31 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 63 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 95 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 127 26 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 15 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 127 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 239 30 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 31 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 95 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 143 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 207 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 255 30 1 + DELTAC2[ ] /* DeltaExceptionC2 */ + PUSHB[ ] /* 3 values pushed */ + 63 30 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 111 30 1 + DELTAC3[ ] /* DeltaExceptionC3 */ + PUSHB[ ] /* 3 values pushed */ + 47 32 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + PUSHB[ ] /* 3 values pushed */ + 111 32 1 + DELTAC1[ ] /* DeltaExceptionC1 */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 10 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 12 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 11 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 20 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 22 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 4 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 4 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 14 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 18 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 4 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 4 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 35 9 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 31 31 31 47 31 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 30 207 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 30 31 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 63 30 79 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 239 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 207 9 223 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 143 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 20 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 17 values pushed */ + 74 0 90 0 106 0 122 0 138 0 154 0 170 0 186 0 8 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 57 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 5 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 19 values pushed */ + 54 6 70 6 86 6 102 6 118 6 134 6 150 6 166 6 182 6 9 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 12 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 0 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 35 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 20 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 9 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 4 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 38 26 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 4 19 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 134 0 150 0 166 0 182 0 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 137 6 153 6 169 6 185 6 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 5 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 23 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 0 31 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 1 31 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 62 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 12 5 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 12 207 12 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 12 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 58 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 58 207 58 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 29 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 47 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 64 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 19 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 21 19 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 42 9 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 34 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 16 42 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 17 9 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 19 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 17 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 31 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 49 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 41 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 23 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 46 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 51 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 35 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 1 7 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 50 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 5 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 57 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 64 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 8 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 0 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 7 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 6 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 11 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 17 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 18 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 9 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 3 + CALL[ ] /* CallFunction */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 1 31 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 4 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 5 values pushed */ + 19 6 35 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 1 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 4 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 18 19 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 18 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 7 31 7 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 5 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 39 58 59 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 46 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 54 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 54 46 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 3 31 3 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 10 46 54 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 10 16 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 14 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 17 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 240 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 31 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 31 223 31 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 223 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 95 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 79 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 31 95 31 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 96 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 224 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 224 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 20 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 20 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 19 3 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 4 6 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 13 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 20 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 40 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 47 30 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 26 207 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 39 9 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 26 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 39 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 24 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 42 18 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 42 207 42 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 18 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 34 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 191 34 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 35 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 21 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 10 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 16 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 25 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 25 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 6 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 2 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 6 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 34 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 23 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 7 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 19 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 5 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 19 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 35 5 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 77 78 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 71 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 71 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 75 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 75 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 64 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 64 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 44 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 75 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 71 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 64 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 64 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 58 44 64 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 58 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 49 44 64 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 52 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 20 21 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 14 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 5 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 223 42 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 42 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 42 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 25 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 5 8 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 1 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 14 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 175 1 191 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 223 1 239 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 1 47 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 1 127 1 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 37 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 1 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 5 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 163 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 13 29 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 7 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 12 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 1 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 6 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 7 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 2 112 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 2 112 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 10 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 8 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 2 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 22 112 22 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 22 112 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 18 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 11 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 16 112 16 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 36 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 31 39 47 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 191 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 223 39 239 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 36 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 28 22 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 6 112 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 7 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 27 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 19 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 9 112 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 9 112 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 19 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 7 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 11 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 10 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 23 112 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 23 112 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 7 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 23 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 9 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 13 112 13 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 17 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 0 112 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 0 112 0 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 2 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 8 112 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 8 112 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 1 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 47 48 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 19 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 33 2 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 12 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 14 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 5 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 25 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 25 112 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 25 112 25 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 29 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 29 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 31 1 47 1 63 1 79 1 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 2 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 33 1 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 21 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 16 33 32 33 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 31 18 47 18 63 18 79 18 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 18 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 2 16 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 39 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 32 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 11 31 11 47 11 63 11 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 11 207 11 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 7 values pushed */ + 128 0 144 0 160 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 38 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 11 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 9 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 36 6 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 223 36 239 36 255 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 7 values pushed */ + 15 36 31 36 47 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 36 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 36 31 36 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 23 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 36 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 12 23 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 15 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 2 31 2 47 2 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 63 7 79 7 95 7 111 7 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 63 2 79 2 95 2 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 17 values pushed */ + 15 0 31 0 47 0 63 0 79 0 95 0 111 0 127 0 8 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 223 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 38 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 22 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 8 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 144 14 160 14 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 55 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 55 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 32 8 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 59 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 66 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 23 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 5 values pushed */ + 99 6 115 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 51 6 67 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 147 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 23 47 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 223 23 239 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 4 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 15 31 15 47 15 63 15 79 15 95 15 111 15 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 112 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 7 31 7 47 7 63 7 79 7 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 25 values pushed */ + 63 23 79 23 95 23 111 23 127 23 143 23 159 23 175 23 191 23 207 23 223 23 239 23 12 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 21 31 21 47 21 63 21 79 21 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 0 31 0 47 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 4 3 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 7 31 7 47 7 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 3 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 6 31 6 47 6 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 2 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 10 31 10 47 10 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 5 31 5 47 5 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 14 31 14 47 14 63 14 79 14 95 14 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 7 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 20 14 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 6 31 6 47 6 63 6 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 4 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 6 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 63 10 79 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 13 31 13 47 13 63 13 79 13 95 13 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 8 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 15 31 15 47 15 63 15 79 15 95 15 111 15 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 15 values pushed */ + 15 21 31 21 47 21 63 21 79 21 95 21 111 21 7 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 20 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 27 14 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 63 34 79 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 34 31 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 23 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 17 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 24 23 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 9 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 7 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 13 values pushed */ + 15 7 31 7 47 7 63 7 79 7 95 7 6 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 15 20 31 20 47 20 63 20 79 20 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 223 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 20 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 5 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 31 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 31 25 47 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 8 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 4 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 25 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 25 207 25 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 3 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 44 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 42 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 33 13 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 42 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 19 33 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 30 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 28 0 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 20 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 32 30 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 24 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 34 6 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 12 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 10 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 31 24 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 223 24 239 24 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 31 24 47 24 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 24 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 79 24 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 239 24 255 24 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 24 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 5 values pushed */ + 239 23 255 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 31 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 223 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 111 23 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 223 23 239 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 31 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 95 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 23 47 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 3 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 176 10 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 20 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 0 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 223 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 6 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 19 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 2 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[11100] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 127 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 239 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 35 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[11100] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 2 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 10 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 25 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 240 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 39 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 160 39 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 96 39 112 39 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 48 39 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 96 39 112 39 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 29 25 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 3 values pushed */ + 160 11 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 7 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 7 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 47 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 21 16 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 16 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 15 7 31 7 47 7 63 7 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 1 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 13 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 0 31 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 61 62 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 7 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 22 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 21 values pushed */ + 58 0 74 0 90 0 106 0 122 0 138 0 154 0 170 0 186 0 202 0 10 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 21 values pushed */ + 54 6 70 6 86 6 102 6 118 6 134 6 150 6 166 6 182 6 198 6 10 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 6 207 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 0 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 31 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 31 8 47 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 175 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 8 63 8 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 223 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 7 values pushed */ + 95 8 111 8 127 8 3 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 207 8 223 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 8 95 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 96 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 240 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 41 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 21 31 21 47 21 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 18 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 8 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 4 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 16 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 24 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 7 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 9 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 10 9 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 4 3 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 1 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 7 4 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 3 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 79 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 19 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RUTG[ ] /* RoundUpToGrid */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 2 values pushed */ + 0 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 8 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 53 54 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 49 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 49 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 10 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + NPUSHB[ ] /* 9 values pushed */ + 15 16 31 16 47 16 63 16 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 4 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 27 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 27 19 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 17 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 10 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 38 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 11 4 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 11 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 27 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 16 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 35 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 27 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 11 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 3 0 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 49 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 53 35 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 55 3 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 82 83 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 36 18 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 38 25 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 43 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 50 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 43 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 64 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 71 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 78 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 33 20 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 14 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 5 values pushed */ + 11 5 27 5 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 27 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 4 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 16 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 9 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 11 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 54 62 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 54 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 34 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 0 34 16 34 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 53 32 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 53 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 0 53 16 53 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 31 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 31 53 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 61 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 63 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 28 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 43 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 35 69 70 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 53 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 8 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 63 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 22 63 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 48 35 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 48 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 55 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 55 48 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 20 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 31 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 31 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 191 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 5 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 15 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 79 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 143 14 159 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 14 207 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 239 14 255 14 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 11 25 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 12 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 0 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 8 31 8 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 3 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 21 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 9 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 1 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 16 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 23 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 8 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 6 8 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 5 2 3 + CALL[ ] /* CallFunction */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 3 14 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 20 22 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 111 0 127 0 143 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 15 0 31 0 47 0 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 0 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 14 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 20 38 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 29 25 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 3 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 2 3 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 11 values pushed */ + 0 3 16 3 32 3 48 3 64 3 5 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + NPUSHB[ ] /* 9 values pushed */ + 48 9 64 9 80 9 96 9 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 0 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 7 values pushed */ + 15 6 31 6 47 6 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + RTHG[ ] /* RoundToHalfGrid */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + RTG[ ] /* RoundToGrid */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 2 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 25 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 13 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 23 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 22 207 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 22 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 22 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 38 26 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 2 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 4 12 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 20 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 11 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 37 22 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 37 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 37 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 138 4 154 4 170 4 186 4 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 9 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + NPUSHB[ ] /* 9 values pushed */ + 133 9 149 9 165 9 181 9 4 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 7 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 43 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 21 23 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 11 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 28 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 239 8 255 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 8 207 8 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 8 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 143 8 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 33 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 15 95 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 143 15 159 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 10 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 18 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 23 0 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 15 18 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 1 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 23 207 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 23 175 23 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 23 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 23 63 23 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 23 127 23 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 15 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 21 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 191 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 16 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 16 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 16 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 19 0 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 10 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 47 37 63 37 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 37 207 37 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 37 175 37 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 37 127 37 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 6 37 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 34 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 25 21 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 7 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 7 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 6 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 6 207 6 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 6 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 1 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 8 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 9 207 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 9 223 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 9 175 9 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 9 127 9 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 49 50 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 17 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 15 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 13 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 9 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 29 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 47 29 63 29 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 29 207 29 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 29 175 29 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 29 127 29 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 3 8 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 20 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 17 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 0 207 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 0 175 0 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 0 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 0 63 0 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 7 values pushed */ + 95 0 111 0 127 0 3 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 3 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 191 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 31 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 30 25 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 25 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 8 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 27 16 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 27 31 27 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 191 27 207 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 27 175 27 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 27 223 27 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 27 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 27 63 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 27 127 27 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 191 27 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 20 16 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 1 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 17 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 12 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 191 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 25 16 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 0 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 21 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 10 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 17 2 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 14 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 14 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 38 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 5 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 37 38 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 36 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 28 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 15 207 15 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 63 15 79 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 15 223 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 15 31 15 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 15 175 15 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 15 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 15 63 15 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 15 127 15 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 8 15 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 28 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 14 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 2 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 15 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 22 2 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 16 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 23 18 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 20 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 38 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 27 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 30 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 42 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 42 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 5 18 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 46 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 43 31 43 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 42 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 46 51 52 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 40 5 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 40 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 40 207 40 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 40 175 40 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 40 127 40 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 37 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 37 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 46 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 43 31 43 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 42 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 13 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 95 22 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 79 22 95 22 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 22 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 12 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 26 207 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 159 26 175 26 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 26 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 26 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 47 26 63 26 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 207 26 223 26 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 6 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 2 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 5 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 74 75 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 10 13 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 32 20 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 47 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 45 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 47 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 52 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 60 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 56 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 68 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 9 73 74 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 60 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 9 12 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 19 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 44 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 45 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 59 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 55 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 67 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 67 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 72 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 7 10 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 40 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 39 40 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 6 8 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 32 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 3 6 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 69 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 69 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 69 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 76 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 83 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 90 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 96 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 103 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 56 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 63 11 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 28 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 10 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 15 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 12 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 3 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 0 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 7 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 16 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 14 16 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 122 13 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 20 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 3 21 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 15 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 8 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 14 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 14 207 14 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 14 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 9 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 14 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 18 1 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 16 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 18 1 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 6 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 8 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 1 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 9 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 9 207 9 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 9 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 111 9 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 12 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 47 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 1 207 1 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 1 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 1 223 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 1 175 1 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 1 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 1 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 1 127 1 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 17 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 22 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 18 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 23 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 24 55 56 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 2 4 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 2 44 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 44 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 51 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 48 49 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 2 4 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 20 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 34 39 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 44 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 10 8 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 15 16 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 11 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 0 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 6 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 21 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 18 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 1 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 23 38 39 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 31 15 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 191 30 207 30 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 23 13 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 13 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 159 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 255 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 19 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 19 207 19 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 19 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 19 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 22 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 95 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 2 127 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 15 2 31 2 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 239 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 175 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 2 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 20 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 2 207 2 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 2 223 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 2 175 2 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 2 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 2 127 2 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 18 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 48 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 46 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 55 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 28 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 11 27 28 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 5 2 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 36 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 25 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 22 9 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 3 values pushed */ + 0 6 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 11 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 13 14 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 4 20 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 1 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 12 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 7 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 8 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 16 0 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 25 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 26 44 45 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 28 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 11 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 17 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 26 3 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 40 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 26 33 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 15 40 41 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 7 14 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 23 40 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 20 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 34 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 33 34 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 33 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 0 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 26 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MDRP[11100] /* MoveDirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 36 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 8 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 25 14 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 32 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 30 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 22 30 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 20 30 31 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 17 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 10 0 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 239 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 95 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 207 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 31 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 111 28 127 28 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 191 28 207 28 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 79 28 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 175 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 28 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 15 28 31 28 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 3 values pushed */ + 63 28 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 27 29 30 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 111 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 191 7 207 7 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 63 7 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 5 values pushed */ + 207 7 223 7 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 15 7 1 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 5 values pushed */ + 159 7 175 7 2 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 255 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 15 7 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 159 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 47 7 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 5 values pushed */ + 111 7 127 7 2 + DELTAP3[ ] /* DeltaExceptionP3 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 18 25 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 21 35 36 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 9 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 14 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 22 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 0 9 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 31 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 11 19 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 2 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 22 25 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 21 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 14 21 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 36 42 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 37 11 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 207 37 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 159 37 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 2 values pushed */ + 38 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 38 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 11 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 49 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 45 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 69 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 7 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 44 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 44 + MDRP[11100] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 4 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 46 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 42 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 35 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 31 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 33 12 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 34 6 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 38 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 37 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 52 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 50 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 39 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 28 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 27 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 41 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 30 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 19 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 9 8 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 16 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 4 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 12 13 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 5 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 10 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 22 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 1 13 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 26 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 16 12 23 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 20 31 20 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 38 23 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 39 9 26 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 57 59 60 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 57 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 51 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 6 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 28 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 45 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 48 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 50 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 53 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 57 2 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 5 17 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 10 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 15 10 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 40 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 36 40 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 36 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 36 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 0 36 16 36 32 36 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 28 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 29 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 7 values pushed */ + 0 29 16 29 32 29 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 32 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 112 33 1 + DELTAP2[ ] /* DeltaExceptionP2 */ + PUSHB[ ] /* 3 values pushed */ + 32 33 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 36 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 25 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 24 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 19 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 13 9 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 19 17 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 0 23 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 25 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 23 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 5 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 24 25 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 16 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 16 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 10 22 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 3 12 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 15 10 31 10 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 28 58 59 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 14 10 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 7 values pushed */ + 42 14 58 14 74 14 3 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 27 3 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 5 values pushed */ + 54 27 70 27 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 3 values pushed */ + 37 27 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 43 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 50 4 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 54 37 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 54 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 56 10 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 56 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 19 34 35 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 19 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 6 12 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 12 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 31 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 31 41 42 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 37 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 34 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 34 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 2 1 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 2 values pushed */ + 1 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 20 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 27 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 33 37 32 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 38 32 37 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 2 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 9 10 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 5 values pushed */ + 64 4 80 4 2 + DELTAP1[ ] /* DeltaExceptionP1 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 26 27 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 17 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 24 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 24 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 1 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 20 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 9 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 9 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 6 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 22 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 32 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 42 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 42 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 41 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 35 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 39 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 32 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 33 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 32 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 33 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 40 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 40 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 34 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 38 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 13 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 8 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 22 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 40 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 26 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 13 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 16 143 144 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 27 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 48 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 60 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 62 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 70 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 74 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 80 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 87 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 91 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 97 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 99 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 103 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 109 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 112 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 119 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 123 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 127 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 132 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 136 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 16 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 140 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 61 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 70 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 70 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 126 73 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 122 123 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 130 119 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 127 58 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 3 values pushed */ + 10 61 70 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 80 14 15 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 80 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 111 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 21 80 111 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 30 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 37 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 41 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 46 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 52 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 61 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 60 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 61 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 107 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 103 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 99 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 62 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 60 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 108 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 104 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 100 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 63 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 58 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 65 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 70 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 96 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 92 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 88 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 75 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 2 values pushed */ + 74 10 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 90 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 94 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 98 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 71 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 73 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 78 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 14 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 81 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 15 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 118 7 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 119 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 132 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 122 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 133 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 123 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 136 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 126 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 137 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 127 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 140 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 130 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 141 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 4 values pushed */ + 17 17 16 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 4 values pushed */ + 4 17 28 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 4 values pushed */ + 10 17 23 4 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 4 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 28 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 33 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 37 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 28 30 3 + CALL[ ] /* CallFunction */ + PUSHB[ ] /* 1 value pushed */ + 37 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 33 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 13 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 31 30 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 23 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 29 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 31 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 31 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 18 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 18 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 5 3 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 31 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 3 values pushed */ + 16 18 29 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 18 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 14 19 20 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 3 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 26 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 35 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 39 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 21 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 4 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 30 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 13 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 7 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 5 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 5 13 14 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 8 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 6 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 6 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 5 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 10 11 3 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 12 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 12 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 29 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 14 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 4 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 4 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 6 10 4 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 3 0 6 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 9 6 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 3 46 47 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 23 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 43 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 43 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 2 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 8 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 8 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 30 46 43 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 30 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 37 9 8 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 16 17 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 14 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 14 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 5 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 5 20 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 14 5 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 2 values pushed */ + 9 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 18 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 20 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 23 1 + MIRP[10100] /* MoveIndirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 32 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 0 23 24 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 1 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 11 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 11 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 0 11 1 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 7 1 11 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 2 values pushed */ + 5 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 9 2 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 13 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 5 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 17 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 19 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 1 value pushed */ + 1 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 1 value pushed */ + 21 + MDRP[10000] /* MoveDirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 15 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 2 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 2 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 0 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 4 0 2 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 7 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 5 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 9 5 7 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 12 9 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 15 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 7 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 7 26 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + MIRP[10100] /* MoveIndirectRelPt */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 10 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 10 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 3 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 3 18 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 10 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 17 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 3 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 24 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PUSHB[ ] /* 3 values pushed */ + 8 32 33 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + SVTCA[0] /* SetFPVectorToAxis */ + PUSHB[ ] /* 1 value pushed */ + 15 + MDAP[1] /* MoveDirectAbsPt */ + PUSHB[ ] /* 1 value pushed */ + 0 + RCVT[ ] /* ReadCVT */ + IF[ ] /* If */ + PUSHB[ ] /* 1 value pushed */ + 0 + MDAP[1] /* MoveDirectAbsPt */ + ELSE[ ] /* Else */ + PUSHB[ ] /* 2 values pushed */ + 0 30 + MIAP[0] /* MoveIndirectAbsPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 2 values pushed */ + 29 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 1 value pushed */ + 1 + MDRP[10000] /* MoveDirectRelPt */ + PUSHB[ ] /* 3 values pushed */ + 21 32 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 3 values pushed */ + 2 21 0 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + PUSHB[ ] /* 1 value pushed */ + 21 + SRP0[ ] /* SetRefPoint0 */ + PUSHB[ ] /* 2 values pushed */ + 7 1 + PUSHB[ ] /* 1 value pushed */ + 10 + CALL[ ] /* CallFunction */ + IF[ ] /* If */ + POP[ ] /* PopTopStack */ + MDRP[11000] /* MoveDirectRelPt */ + ELSE[ ] /* Else */ + MIRP[10100] /* MoveIndirectRelPt */ + EIF[ ] /* EndIf */ + PUSHB[ ] /* 3 values pushed */ + 28 0 21 + SRP1[ ] /* SetRefPoint1 */ + SRP2[ ] /* SetRefPoint2 */ + IP[ ] /* InterpolatePts */ + IUP[0] /* InterpolateUntPts */ + IUP[1] /* InterpolateUntPts */ + + + + + + + + + Copyright 2011 Google Inc. All Rights Reserved. + + + Roboto + + + Regular + + + Roboto + + + Roboto + + + Version 2.137; 2017 + + + Roboto-Regular + + + Roboto is a trademark of Google. + + + Google + + + Google.com + + + Christian Robertson + + + Licensed under the Apache License, Version 2.0 + + + http://www.apache.org/licenses/LICENSE-2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontDirectoriesTestHelper.cs b/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontDirectoriesTestHelper.cs new file mode 100644 index 0000000000..ea662b6419 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontDirectoriesTestHelper.cs @@ -0,0 +1,203 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Test infrastructure + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tests.Helpers +{ + public class FontDirectoriesTestHelper + { + private static string _fontFolder = string.Empty; + private static List _fontFolders = new List(); + private static string _testOutputPath = @"c:\epplusTest\Fonts\"; + private static bool _testOutputAvailable = false; + private static bool _initialized = false; + private static object _syncRoot = new object(); + + /// + /// Gets the font folder path (for reading test fonts) + /// + public static string FontFolder => _fontFolder; + + /// + /// Gets the list of font folder paths (for reading test fonts) + /// + public static List FontFolders => new List(_fontFolders); + + /// + /// Gets the test output path for saving subset fonts (c:\epplusTest\Fonts\) + /// Returns null if path is not available (e.g. in CI/CD) + /// + public static string TestOutputPath => _testOutputAvailable ? _testOutputPath : null; + + /// + /// Gets whether test output path is available (false in CI/CD environments) + /// + public static bool IsTestOutputAvailable => _testOutputAvailable; + + /// + /// Initializes test environment. Thread-safe singleton. + /// Call this from [ClassInitialize] in each test class. + /// + /// MSTest context (unused but required by MSTest) + public static void ClassInitialize(TestContext testContext) + { + if (!_initialized) + { + lock (_syncRoot) + { + if (!_initialized) + { + // Input folder (test fonts from project) - ALWAYS AVAILABLE + _fontFolder = Path.Combine(AppContext.BaseDirectory, "Fonts"); + _fontFolders = new List { _fontFolder }; + + // Output folder (c:\epplusTest\Fonts\) - OPTIONAL + // Check if c:\epplusTest exists (developer machines only) + var epplusTestRoot = @"c:\epplusTest"; + if (Directory.Exists(epplusTestRoot)) + { + _testOutputAvailable = true; + TryCreateTestOutputPath(); + } + else + { + _testOutputAvailable = false; + } + + OpenTypeFonts.ClearFontCache(); + _initialized = true; + } + } + } + } + + /// + /// Saves a font to the test output folder. + /// SKIPS silently if test output path is not available (CI/CD). + /// If the file exists, it will be deleted first. + /// + /// Font to save + /// Filename (e.g. "subset_Roboto_abc.ttf") + /// FileInfo for the saved file, or null if output not available + public static FileInfo SaveFontToOutput(OpenTypeFont font, string fileName) + { + if (!_testOutputAvailable) + { + // Silently skip in CI/CD - this is for manual inspection only + return null; + } + + if (font == null) + throw new ArgumentNullException(nameof(font)); + + if (string.IsNullOrWhiteSpace(fileName)) + throw new ArgumentException("Filename cannot be empty", nameof(fileName)); + + TryCreateTestOutputPath(); + + var fi = new FileInfo(_testOutputPath + fileName); + if (fi.Exists) + { + fi.Delete(); + } + + var bytes = font.Serialize(); + File.WriteAllBytes(fi.FullName, bytes); + + return fi; + } + + /// + /// Gets a FileInfo for an output file, creating subdirectories if needed. + /// Returns null if test output path is not available (CI/CD). + /// + /// Subdirectory under c:\epplusTest\Fonts\ (e.g. "Roboto") + /// Filename (e.g. "subset_abc.ttf") + /// FileInfo for the output file, or null if output not available + public static FileInfo GetOutputFile(string subPath, string fileName) + { + if (!_testOutputAvailable) + { + return null; + } + + var path = _testOutputPath + subPath; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + if (!path.EndsWith("\\")) + { + path += "\\"; + } + + return new FileInfo(path + fileName); + } + + /// + /// Tries to create the test output path. Silent fail if not possible. + /// + private static void TryCreateTestOutputPath() + { + if (!_testOutputAvailable) + return; + + try + { + if (!Directory.Exists(_testOutputPath)) + { + Directory.CreateDirectory(_testOutputPath); + } + } + catch + { + // Silent fail - output is optional + _testOutputAvailable = false; + } + } + + /// + /// Checks if a font file exists in the output folder. + /// Returns false if test output path is not available. + /// + /// Filename to check + /// True if file exists + public static bool ExistsOutputFont(string fileName) + { + if (!_testOutputAvailable) + return false; + + var fi = new FileInfo(_testOutputPath + fileName); + return fi.Exists; + } + + /// + /// Deletes a font file from the output folder if it exists. + /// Skips silently if test output path is not available. + /// + /// Filename to delete + public static void DeleteOutputFont(string fileName) + { + if (!_testOutputAvailable) + return; + + var fi = new FileInfo(_testOutputPath + fileName); + if (fi.Exists) + { + fi.Delete(); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontTestHelper.cs b/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontTestHelper.cs new file mode 100644 index 0000000000..650b81516f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Helpers/FontTestHelper.cs @@ -0,0 +1,214 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.Helpers +{ + /// + /// Shared test utilities for font testing + /// + public static class FontTestHelper + { + /// + /// Counts the total number of ligatures in a font's GSUB table + /// + /// Font to analyze + /// Total number of ligature rules + public static int CountLigatures(OpenTypeFont font) + { + if (font?.GsubTable == null) + return 0; + + int count = 0; + + foreach (var lookup in font.GsubTable.LookupList.Lookups) + { + // Lookup Type 4 = Ligature Substitution + if (lookup.LookupType == 4) + { + foreach (var subtable in lookup.SubTables) + { + var ligSubtable = subtable as LigatureSubstSubTable; + if (ligSubtable?.LigatureSets != null) + { + foreach (var ligatureSet in ligSubtable.LigatureSets.Values) + { + count += ligatureSet.Ligatures.Count; + } + } + } + } + } + + return count; + } + + /// + /// Asserts that a font passes validation + /// + /// Font to validate + /// Minimum severity level for errors + public static void AssertFontValid( + OpenTypeFont font, + FontValidationSeverity severity = FontValidationSeverity.Error) + { + var validator = new FontValidator(); + var report = validator.Validate(font, severity); + + if (!report.IsValid) + { + var errorMessages = report.Errors + .Select(e => $" [{e.Severity}] {e.ParentResult.TableName ?? "General"}: {e.Message}") + .ToList(); + + var message = string.Format( + "Font validation failed with {0} error(s):\n{1}", + report.Errors.Count(), + string.Join("\n", errorMessages)); + + throw new AssertFailedException(message); + } + } + + /// + /// Creates a subset and serializes it to bytes + /// + /// Name of font to load + /// Text to subset + /// Folders to search for fonts + /// Serialized subset bytes + public static byte[] SubsetAndSerialize( + string fontName, + string text, + List fontFolders) + { + var font = OpenTypeFonts.LoadFont(fontName, FontSubFamily.Regular); + var subset = font.CreateSubset(text); + return subset.Serialize(); + } + + /// + /// Creates a subset and serializes it to bytes (char array overload) + /// + public static byte[] SubsetAndSerialize( + string fontName, + char[] chars, + List fontFolders) + { + var font = OpenTypeFonts.LoadFont(fontName, FontSubFamily.Regular); + var subset = font.CreateSubset(chars); + return subset.Serialize(); + } + + /// + /// Performs a full roundtrip: subset → serialize → parse → validate + /// + /// Name of font to load + /// Text to subset + /// Folders to search for fonts + /// Parsed subset font (validated) + public static OpenTypeFont RoundtripSubset( + string fontName, + string text, + List fontFolders) + { + var font = OpenTypeFonts.LoadFont(fontName, FontSubFamily.Regular); + var subset = font.CreateSubset(text); + var bytes = subset.Serialize(); + + var parsed = new OpenTypeFont(bytes); + + AssertFontValid(parsed); + + return parsed; + } + + /// + /// Performs a full roundtrip with char array + /// + public static OpenTypeFont RoundtripSubset( + string fontName, + char[] chars, + List fontFolders) + { + var font = OpenTypeFonts.LoadFont(fontName, FontSubFamily.Regular); + var subset = font.CreateSubset(chars); + var bytes = subset.Serialize(); + + var parsed = new OpenTypeFont(bytes); + + AssertFontValid(parsed); + + return parsed; + } + + /// + /// Gets the total number of glyphs in a subset for specific characters + /// + /// Original font + /// Characters to check + /// Number of unique glyph IDs needed + public static int GetExpectedGlyphCount(OpenTypeFont font, char[] chars) + { + var glyphIds = new HashSet(); + + // Always include .notdef + glyphIds.Add(0); + + // Map characters to glyph IDs + foreach (var ch in chars) + { + if (font.CmapTable.TryGetGlyphId(ch, out ushort glyphId)) + { + glyphIds.Add(glyphId); + } + } + + return glyphIds.Count; + } + + /// + /// Checks if a font has a specific lookup type in GSUB + /// + public static bool HasGsubLookupType(OpenTypeFont font, ushort lookupType) + { + if (font?.GsubTable == null) + return false; + + return font.GsubTable.LookupList.Lookups + .Any(lookup => lookup.LookupType == lookupType); + } + + /// + /// Gets all ligature lookup types present in font + /// + public static List GetGsubLookupTypes(OpenTypeFont font) + { + if (font?.GsubTable == null) + return new List(); + + return font.GsubTable.LookupList.Lookups + .Select(lookup => lookup.LookupType) + .Distinct() + .OrderBy(type => type) + .ToList(); + } + + /// + /// Saves a font to a file (useful for manual inspection) + /// + public static void SaveFontForInspection( + OpenTypeFont font, + string filename) + { + var bytes = font.Serialize(); + var tempPath = Path.Combine(Path.GetTempPath(), filename); + File.WriteAllBytes(tempPath, bytes); + Console.WriteLine($"Font saved to: {tempPath}"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Integration/EnsureWrappingWithFreeFonts.cs b/src/EPPlus.Fonts.OpenType.Tests/Integration/EnsureWrappingWithFreeFonts.cs new file mode 100644 index 0000000000..595896c5df --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Integration/EnsureWrappingWithFreeFonts.cs @@ -0,0 +1,142 @@ +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Tests.Integration +{ + [TestClass] + public class EnsureWrappingWithFreeFonts : FontTestBase + { + const double MaxWidthInPoints = 47.177401574803149606299212598425d; + const string TestText = "Open sans"; + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void TestWrappingOpenSans() + { + var mf = new MeasurementFont() + { + FontFamily = "Open Sans", + Size = 12f, + Style = MeasurementFontStyles.Regular + }; + + var tle = TestFolderEngine.GetTextLayoutEngineForFont(mf); + + var resultStrings = tle.WrapText(TestText, mf.Size, MaxWidthInPoints); + Assert.AreEqual(2, resultStrings.Count); + Assert.AreEqual("Open", resultStrings[0]); + Assert.AreEqual("sans", resultStrings[1]); + } + + [TestMethod] + public void TestWrappingUnicaOne() + { + var mf = new MeasurementFont() + { + FontFamily = "Unica One", + Size = 12f, + Style = MeasurementFontStyles.Regular + }; + + var tle = SystemFontsEngine.GetTextLayoutEngineForFont(mf); + + var resultStrings = tle.WrapText(TestText, mf.Size, MaxWidthInPoints); + Assert.AreEqual(2, resultStrings.Count); + Assert.AreEqual("Open", resultStrings[0]); + Assert.AreEqual("sans", resultStrings[1]); + } + + [TestMethod] + public void TestWrappingPinyon() + { + var mf = new MeasurementFont() + { + FontFamily = "Pinyon Script", + Size = 12f, + Style = MeasurementFontStyles.Regular + }; + + var tle = TestFolderEngine.GetTextLayoutEngineForFont(mf); + + var resultStrings = tle.WrapText(TestText, mf.Size, MaxWidthInPoints); + Assert.AreEqual(1, resultStrings.Count); + Assert.AreEqual("Open sans", resultStrings[0]); + } + + [TestMethod] + public void TestWrappingOi() + { + var mf = new MeasurementFont() + { + FontFamily = "Oi", + Size = 12f, + Style = MeasurementFontStyles.Regular + }; + + var tle = TestFolderEngine.GetTextLayoutEngineForFont(mf); + + var resultStrings = tle.WrapText(TestText, mf.Size, MaxWidthInPoints); + Assert.AreEqual(3, resultStrings.Count); + Assert.AreEqual("Ope", resultStrings[0]); + Assert.AreEqual("n", resultStrings[1]); + Assert.AreEqual("sans", resultStrings[2]); + } + + [TestMethod] + public void TestWrappingLoremIpsum20Paragraphs() + { + var Lorem20Str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in. Fusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh. Maecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem. Integer congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet. Sed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus. Cras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada. Aliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus. Nullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris. Donec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.Suspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.Cras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.Quisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.Nam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis. Fusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci. Vivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida. In in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum. Donec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo. Donec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum. Nunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; + var savedCompareString = "Lorem ipsum\r\ndolor sit\r\namet,\r\nconsectetur\r\nadipiscing\r\nelit. Nulla\r\npulvinar\r\ninterdum\r\nimperdiet.\r\nPraesent ut\r\nauctor urna.\r\nPhasellus\r\nsollicitudin\r\nquam vitae\r\nest convallis,\r\neu mattis\r\nlorem\r\nefficitur.\r\nMauris nulla\r\nlibero,\r\ntincidunt id\r\nipsum non,\r\nlobortis\r\ntristique\r\nmauris.\r\nDonec ut\r\nenim sed\r\nenim\r\nfermentum\r\nmolestie vel\r\nquis odio.\r\nMorbi a\r\nfermentum\r\nmassa, sit\r\namet ultrices\r\nest. Aenean\r\nante mi,\r\nfermentum\r\nnec rhoncus\r\net, vulputate\r\nvel sapien.\r\nDonec\r\ntempus, leo\r\nquis luctus\r\nrhoncus,\r\naugue odio\r\npharetra\r\nlibero, ac\r\nblandit urna\r\nturpis sed\r\ndiam.\r\nVivamus\r\naugue purus,\r\neleifend et\r\njusto\r\nfacilisis,\r\nimperdiet\r\nrhoncus sem.\r\nQuisque\r\naccumsan\r\npellentesque\r\nelit, eget\r\nfinibus\r\nmassa\r\naccumsan in.\r\nFusce eu\r\naccumsan\r\nenim. Cras\r\npulvinar\r\nenim vel\r\ntellus lacinia,\r\nconsectetur\r\neuismod\r\ntortor\r\nconsectetur.\r\nPraesent\r\ntincidunt\r\npretium eros,\r\nac auctor\r\nmagna luctus\r\nsed. Ut porta\r\nlectus quam,\r\nnon ornare\r\nmauris\r\nlacinia sit\r\namet. Nullam\r\negestas\r\ndolor quis\r\nmagna\r\nporttitor, ac\r\niaculis nisi\r\nhendrerit.\r\nProin at\r\nmollis lacus,\r\nin porttitor\r\nnunc.\r\nAliquam erat\r\nvolutpat. Sed\r\nvel egestas\r\nrisus, at\r\naliquam\r\narcu.\r\nVestibulum\r\nquis lobortis\r\nnulla. Etiam\r\npellentesque\r\nauctor nulla,\r\neget\r\ntincidunt felis\r\nrhoncus id.\r\nSed metus\r\nante, efficitur\r\nid dui eu,\r\nfermentum\r\nmollis odio.\r\nPhasellus\r\nullamcorper\r\niaculis augue\r\nvel\r\nconsequat.\r\nEtiam\r\nfringilla\r\neuismod\r\ninterdum. Ut\r\nmolestie\r\nmassa id\r\nfringilla\r\nlobortis.\r\nVestibulum\r\nmalesuada,\r\nante vel\r\nmattis\r\nultrices, sem\r\nante\r\nmolestie\r\naugue, non\r\ntristique dui\r\nmi non nibh.\r\nMaecenas\r\ndictum, sem\r\neget\r\nconvallis\r\nrhoncus,\r\nlacus enim\r\nporta neque,\r\nin posuere\r\ndui ex a\r\nsapien. Nam\r\nlacus nibh,\r\nposuere sed\r\nelit eget,\r\ncondimentu\r\nm facilisis\r\nligula. Cras\r\nconsectetur\r\nlacus\r\nullamcorper\r\nvelit aliquet\r\nbibendum\r\neget vel\r\nnulla.\r\nAenean\r\nvarius ac\r\nerat quis\r\nullamcorper.\r\nDonec\r\nlaoreet arcu\r\na lorem\r\nvolutpat\r\nfaucibus.\r\nVivamus\r\nvehicula leo\r\nut erat luctus\r\nscelerisque.\r\nMorbi\r\nposuere ex\r\net magna\r\negestas\r\nfacilisis.\r\nFusce\r\nscelerisque\r\nvolutpat erat\r\nbibendum\r\nhendrerit.\r\nNam blandit\r\nmi ut metus\r\npulvinar, vel\r\ntempus lacus\r\neuismod.\r\nQuisque\r\nimperdiet sit\r\namet sapien\r\nsed ultricies.\r\nPhasellus\r\nsodales,\r\nipsum vitae\r\ntincidunt\r\nfacilisis,\r\nnulla ligula\r\nfaucibus\r\nfelis, eget\r\nvehicula ante\r\nlacus eu\r\nlorem.\r\nInteger\r\ncongue diam\r\nac viverra\r\ntristique.\r\nCurabitur\r\ntristique\r\ndolor quis\r\nquam\r\npretium, et\r\nscelerisque\r\nquam\r\ndictum.\r\nMaecenas\r\nvitae sodales\r\nligula.\r\nPellentesque\r\nmaximus\r\ndiam vel\r\nporta\r\nconvallis. Ut\r\naliquam eros\r\nquis porta\r\npellentesque.\r\nFusce in ex\r\nut mi\r\negestas\r\ncursus.\r\nAliquam erat\r\nvolutpat.\r\nCras laoreet\r\ncondimentu\r\nm laoreet.\r\nSed eget\r\nfacilisis\r\ntellus. Morbi\r\nviverra odio\r\nsed odio\r\nplacerat\r\nmollis. Duis\r\nturpis metus,\r\ndignissim\r\nvarius urna\r\nquis, viverra\r\ndignissim\r\ndui. Vivamus\r\nviverra at\r\nnisi quis\r\nconvallis.\r\nSuspendisse\r\nfringilla risus\r\net ante\r\nsollicitudin,\r\nsed eleifend\r\nsem placerat.\r\nProin\r\npretium\r\nblandit arcu,\r\neget rhoncus\r\nrisus\r\nhendrerit at.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nPhasellus\r\nvulputate\r\nefficitur\r\nmaximus.\r\nCras blandit\r\nnulla eu nisi\r\nauctor\r\ntempus. Sed\r\npretium lacus\r\nac magna\r\nvestibulum,\r\naliquam\r\nfaucibus orci\r\nluctus.\r\nMauris enim\r\nlorem, varius\r\nut ante quis,\r\nvarius\r\nviverra\r\nlectus. Fusce\r\nblandit nibh\r\nvel feugiat\r\nefficitur.\r\nDonec\r\nmaximus id\r\njusto ac\r\nmollis.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus orci\r\nluctus et\r\nultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nplacerat\r\nlectus et\r\npurus\r\ndictum, id\r\ncongue nisi\r\neuismod.\r\nMaecenas\r\neuismod\r\nfermentum\r\ndiam, sit\r\namet gravida\r\nmagna\r\nsuscipit a.\r\nQuisque\r\nconsectetur\r\narcu eu nunc\r\nsodales\r\nscelerisque.\r\nNulla non\r\ntincidunt\r\nnulla.\r\nPellentesque\r\nut tortor vel\r\nenim\r\nconvallis\r\nmalesuada.\r\nAliquam\r\nultricies\r\nbibendum\r\nultrices.\r\nMauris\r\nrutrum ac\r\nnisl vel\r\nluctus.\r\nDonec quis\r\nnibh vitae\r\norci ultricies\r\ngravida.\r\nAliquam\r\nvitae velit\r\nporttitor\r\nlorem\r\nbibendum\r\nfringilla\r\nvolutpat a\r\neros.\r\nCurabitur at\r\ncommodo\r\ntortor. Etiam\r\nultricies,\r\nneque et\r\niaculis\r\neuismod,\r\ndiam ligula\r\nluctus mi,\r\nvitae lobortis\r\nfelis lorem eu\r\nnulla. Sed a\r\nsemper ex.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNulla mauris\r\nelit, pulvinar\r\nac tortor et,\r\nluctus\r\nhendrerit\r\nnisl. In\r\negestas\r\nauctor urna\r\nvitae laoreet.\r\nPraesent\r\nbibendum\r\negestas\r\nconvallis.\r\nProin non\r\nsuscipit\r\ntellus. Nullam\r\nat nibh in\r\nurna laoreet\r\nsodales non\r\nvel tellus.\r\nDonec in\r\nenim dui.\r\nPhasellus\r\nquis quam\r\ntincidunt,\r\npellentesque\r\nlorem ac,\r\nscelerisque\r\nneque.\r\nInteger nec\r\ntempus urna.\r\nDonec elit\r\nmassa,\r\neleifend eu\r\nsapien sit\r\namet, mollis\r\npellentesque\r\nest. Nullam\r\ntristique\r\ntellus iaculis\r\narcu\r\nconsectetur\r\npretium. Sed\r\nvenenatis\r\nconvallis\r\nscelerisque.\r\nSuspendisse\r\nvarius urna\r\nsit amet\r\npurus\r\naccumsan, id\r\nultricies erat\r\nefficitur. Cras\r\nnon ipsum\r\neget nulla\r\nefficitur\r\ncommodo sit\r\namet non\r\nlacus. Proin\r\nviverra enim\r\nsit amet\r\nenim tempus\r\nullamcorper.\r\nClass aptent\r\ntaciti\r\nsociosqu ad\r\nlitora\r\ntorquent per\r\nconubia\r\nnostra, per\r\ninceptos\r\nhimenaeos.\r\nDuis ac\r\nmassa\r\ninterdum,\r\ngravida ex\r\negestas,\r\nfinibus\r\npurus. Nunc\r\nconsectetur\r\ncommodo\r\nlacus, ac\r\nconvallis\r\nquam\r\nlobortis eu.\r\nSed convallis\r\ntempor\r\ncommodo.\r\nNulla sed\r\nconvallis\r\nmauris.\r\nDonec\r\nvenenatis\r\nnisi est, ac\r\nullamcorper\r\nmi pretium\r\nquis. Donec\r\nvitae eros at\r\nipsum\r\ninterdum\r\nscelerisque\r\nnec vitae\r\nnisi. Sed\r\nvestibulum\r\nerat ac\r\nbibendum\r\ndapibus.\r\nMorbi nec\r\nelit id quam\r\ntristique\r\ncursus id sed\r\nsem.\r\nPraesent non\r\nante enim.\r\nPellentesque\r\nhabitant\r\nmorbi\r\ntristique\r\nsenectus et\r\nnetus et\r\nmalesuada\r\nfames ac\r\nturpis\r\negestas.\r\nPraesent non\r\nmauris dui.\r\nAliquam\r\nrhoncus\r\nmattis ante\r\nsed\r\nvenenatis.\r\nVivamus\r\nvehicula sed\r\nsapien sed\r\ndictum. In\r\naliquet, urna\r\nefficitur\r\ntincidunt\r\nlobortis, nibh\r\njusto\r\ntristique\r\npurus, sed\r\nvolutpat risus\r\nmagna et\r\nlibero.Suspe\r\nndisse lectus\r\njusto, varius\r\neget arcu et,\r\nsemper\r\nlaoreet erat.\r\nQuisque\r\neget lacus\r\nornare,\r\npellentesque\r\nerat sit amet,\r\nvulputate\r\nfelis. Duis\r\nluctus,\r\nmassa a\r\npellentesque\r\nmollis,\r\nmassa elit\r\nconvallis mi,\r\nvel\r\nbibendum ex\r\nex eu purus.\r\nSuspendisse\r\nvel\r\nfermentum\r\nurna, ac\r\ncommodo\r\nenim. Mauris\r\ntincidunt\r\ncursus elit, a\r\nvolutpat\r\nlibero\r\ncommodo et.\r\nEtiam\r\ndapibus\r\nlibero\r\nvenenatis\r\ntellus\r\nlobortis, vel\r\nlacinia elit\r\nfaucibus.\r\nMaecenas\r\nsemper sed\r\nquam quis\r\nfinibus.\r\nInteger\r\nefficitur,\r\nlibero\r\nimperdiet\r\nsollicitudin\r\ncommodo,\r\nelit arcu\r\nvulputate est,\r\neget finibus\r\nmi urna sit\r\namet magna.\r\nCras\r\nullamcorper\r\nconsequat\r\nornare.\r\nFusce\r\nconvallis\r\nnunc vel\r\nrisus cursus,\r\nat maximus\r\nligula cursus.\r\nPellentesque\r\nvulputate\r\nrisus libero,\r\neget cursus\r\nnibh sodales\r\nsed. Donec\r\naccumsan\r\nsem et\r\nmassa\r\nsemper, id\r\ndignissim\r\nvelit\r\nvehicula.Cra\r\ns cursus\r\nipsum ac\r\nerat\r\nvehicula, nec\r\niaculis purus\r\ndictum.\r\nQuisque\r\nlacinia elit\r\nvitae leo\r\ndictum, vel\r\ndignissim\r\nvelit dapibus.\r\nAenean sem\r\nnisi, faucibus\r\ninterdum\r\njusto eu,\r\neuismod\r\nporttitor ex.\r\nMorbi et\r\nlectus lectus.\r\nDuis neque\r\nfelis, suscipit\r\nat\r\nscelerisque\r\neu,\r\nscelerisque\r\nid orci.\r\nCurabitur et\r\nplacerat\r\nipsum. Proin\r\ngravida\r\nsapien nisl,\r\net varius\r\nipsum mollis\r\nnec. Quisque\r\ndignissim\r\nconsectetur\r\nfeugiat.\r\nAenean eros\r\npurus,\r\nlaoreet\r\ninterdum\r\nrutrum at,\r\naliquet sit\r\namet lectus.\r\nDonec\r\ngravida\r\nlorem ut\r\ntincidunt\r\nlaoreet.\r\nDonec\r\nconsequat\r\nviverra ligula,\r\nin accumsan\r\nmi bibendum\r\nscelerisque.\r\nQuisque ac\r\nrisus justo.\r\nMorbi magna\r\narcu,\r\negestas nec\r\nluctus\r\ncommodo,\r\ncursus eget\r\nnunc.\r\nVivamus\r\neuismod\r\nlorem ex, et\r\nmaximus\r\nfelis\r\nhendrerit\r\neget. Nullam\r\nullamcorper\r\neuismod\r\nligula, et\r\niaculis ligula\r\nultricies a.\r\nFusce\r\naliquam,\r\nenim vel\r\nfermentum\r\nultrices, elit\r\nquam\r\nsemper erat,\r\nvitae semper\r\nvelit augue\r\nnon\r\nmagna.Quis\r\nque maximus\r\nsemper arcu,\r\nid\r\npellentesque\r\nest tempus\r\na. Phasellus\r\nlacus elit,\r\nauctor sit\r\namet lacinia\r\na, dapibus\r\nvitae velit.\r\nPhasellus ut\r\npharetra\r\njusto, ut\r\nultricies erat.\r\nSed molestie\r\nsapien vel\r\ninterdum\r\nlobortis.\r\nNulla facilisi.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus orci\r\nluctus et\r\nultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nnec mauris\r\nquis nisi\r\nvulputate\r\ngravida quis\r\nnec\r\nvelit.Nam et\r\ncongue\r\nipsum. Nulla\r\nvel elit non\r\ndolor mollis\r\naliquet vel at\r\nmagna.\r\nPellentesque\r\nnec facilisis\r\nelit. In\r\nvulputate\r\nquis sem\r\nporta\r\nsuscipit.\r\nNullam sed\r\nex ornare\r\nnibh suscipit\r\nmattis quis\r\nnon lacus.\r\nMauris vel ex\r\nurna.\r\nVivamus\r\nultricies\r\nsapien sit\r\namet sapien\r\nvehicula\r\ngravida.\r\nDonec\r\nfeugiat\r\nvolutpat\r\nquam.\r\nVestibulum\r\nauctor\r\ndictum nisl,\r\nid hendrerit\r\nmetus\r\nullamcorper\r\nsed. Nulla\r\nmaximus\r\nlacus vel\r\nmollis\r\nmaximus.\r\nNulla laoreet\r\nplacerat\r\nquam eu\r\nviverra.\r\nEtiam feugiat\r\naccumsan\r\nnisl a\r\ncondimentu\r\nm. Sed\r\nultricies ante\r\nante, ac\r\nauctor ligula\r\ngravida nec.\r\nPraesent a\r\nneque\r\ndignissim,\r\nsagittis felis\r\nsit amet,\r\ncondimentu\r\nm turpis.\r\nFusce at leo\r\nvel est\r\nblandit\r\nmalesuada.\r\nPellentesque\r\net neque non\r\nmetus\r\npellentesque\r\nimperdiet.\r\nPraesent\r\npellentesque\r\nlacinia lorem,\r\net tristique\r\ntellus efficitur\r\nid.\r\nSuspendisse\r\naliquet\r\nultricies justo\r\nvitae\r\ninterdum.\r\nCras tristique\r\nviverra\r\nquam, eget\r\ngravida mi\r\nfermentum\r\nimperdiet.\r\nSed\r\nimperdiet\r\nvitae purus\r\nut volutpat.\r\nNulla lacinia\r\nelit in\r\nfermentum\r\nconsectetur.\r\nPhasellus\r\ncommodo ut\r\nnisl sit amet\r\nsagittis. Duis\r\nac ornare\r\norci.\r\nVivamus vel\r\nenim\r\nposuere,\r\npharetra ex\r\nvel,\r\nelementum\r\nest.\r\nVestibulum\r\ncommodo\r\nluctus metus\r\neget\r\nmaximus.\r\nSuspendisse\r\na nulla a\r\nodio eleifend\r\nfaucibus.\r\nSuspendisse\r\nsemper lacus\r\nnon porttitor\r\naliquet. Cras\r\nac\r\nscelerisque\r\nmagna, et\r\npulvinar\r\njusto. Integer\r\ncursus\r\npulvinar\r\nfringilla.\r\nMauris\r\nimperdiet\r\nnibh sit amet\r\ntempor\r\nlaoreet.\r\nMorbi\r\ntincidunt\r\ntortor ex, sit\r\namet\r\nmaximus\r\npurus\r\ntristique\r\nquis.\r\nQuisque sed\r\nhendrerit\r\nvelit. Mauris\r\nmattis nibh\r\nut eros\r\nluctus, eget\r\nmattis massa\r\nauctor.\r\nPhasellus eu\r\nneque at\r\naugue\r\ngravida\r\nsagittis nec\r\nnon tortor.\r\nEtiam\r\nporttitor sem\r\nsodales mi\r\nullamcorper\r\ngravida. In in\r\ndictum orci.\r\nIn vitae\r\nvestibulum\r\nquam. Cras\r\naugue eros,\r\ntincidunt ac\r\nelit posuere,\r\nsollicitudin\r\nefficitur\r\nlectus.\r\nPraesent\r\nquis sodales\r\nnisl. Proin sit\r\namet\r\nmolestie est.\r\nIn commodo\r\nmauris vel\r\nmauris\r\nefficitur, nec\r\nmollis mauris\r\nsagittis. Cras\r\nligula nibh,\r\negestas sit\r\namet eros in,\r\nlacinia\r\ntristique\r\nmagna. Cras\r\nrisus libero,\r\nlacinia eget\r\nlibero vitae,\r\nmaximus\r\naliquet nibh.\r\nMauris id\r\nsodales\r\npurus, vitae\r\ndictum\r\nlectus. Cras\r\nconsectetur\r\nligula velit,\r\ntempus\r\npulvinar\r\nlacus\r\nporttitor\r\nvitae.\r\nPhasellus\r\neget tellus\r\nipsum.\r\nDonec\r\ninterdum\r\nlaoreet elit\r\nnon\r\nvestibulum.\r\nCras sed\r\nurna\r\nullamcorper,\r\naliquam erat\r\neget, porta\r\norci.\r\nVestibulum\r\neget congue\r\nnulla. Sed\r\nsem tortor,\r\neuismod at\r\nrutrum id,\r\nsagittis a\r\nnunc. Duis in\r\nnibh facilisis,\r\ndignissim\r\npurus ut,\r\nhendrerit\r\nmagna. Sed\r\nsemper ligula\r\nid massa\r\nelementum,\r\nnon\r\nmalesuada\r\nvelit egestas.\r\nNullam\r\ndictum, mi\r\nnec euismod\r\nsagittis,\r\nligula leo\r\nullamcorper\r\ndolor, quis\r\nfaucibus\r\nodio metus\r\neget magna.\r\nUt gravida\r\nmetus non\r\nmetus\r\nbibendum\r\nbibendum. In\r\nsagittis\r\neleifend\r\naliquet.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNam mollis\r\nsagittis felis,\r\nin faucibus\r\ntortor pretium\r\nvel. Nam nec\r\nenim metus.\r\nDonec in\r\naugue arcu.\r\nProin non\r\nlobortis\r\npurus, sit\r\namet lacinia\r\nelit.\r\nSuspendisse\r\nquis eros\r\ncondimentu\r\nm, blandit\r\njusto sit\r\namet,\r\nlobortis nisl.\r\nSuspendisse\r\nmaximus\r\nmassa sed\r\nurna tempor\r\nornare. Nunc\r\nmalesuada\r\npurus odio,\r\neu luctus\r\nlectus auctor\r\nnec. Morbi\r\nauctor\r\npellentesque\r\nauctor. Sed\r\nullamcorper,\r\nex vitae\r\naliquam\r\nvulputate, est\r\ndiam feugiat\r\nmi, id\r\nporttitor\r\nlectus orci ac\r\nleo. Donec\r\nsit amet velit\r\npulvinar,\r\nvenenatis\r\nturpis ut,\r\ninterdum\r\nligula.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nVestibulum\r\neu lacus\r\nurna.\r\nMaecenas\r\nsem nulla,\r\naccumsan eu\r\nultricies sed,\r\ntempor vel\r\nmagna. Cras\r\naliquet\r\nsollicitudin\r\nsapien ac\r\npulvinar.\r\nPraesent ac\r\nsodales mi.\r\nInteger vitae\r\nmauris\r\nmassa.\r\nMaecenas\r\niaculis orci et\r\nfaucibus\r\ninterdum.\r\nNunc nec\r\nmaximus\r\nfelis, sed\r\nfinibus\r\nquam.\r\nPellentesque\r\nfelis massa,\r\nvestibulum in\r\ntellus vitae,\r\ncongue\r\ntincidunt\r\njusto. Nunc\r\nvitae enim\r\nmalesuada,\r\nbibendum\r\nante nec,\r\nvarius tellus.\r\nPraesent\r\nvitae nisi id\r\nquam auctor\r\nlacinia at\r\nnon quam.\r\nNam nec\r\nligula sit\r\namet felis\r\nauctor\r\nsagittis.\r\nNunc in risus\r\neu urna\r\nvarius\r\nlaoreet quis\r\nsit amet felis.\r\nMorbi varius\r\ntempor orci,\r\neu\r\nvestibulum\r\nnunc\r\nvestibulum\r\nac. Nunc\r\nvehicula velit\r\neleifend\r\nconsequat\r\nporta.\r\nSuspendisse\r\nmaximus\r\ndapibus orci,\r\nin vulputate\r\nmassa\r\npretium ac.\r\nQuisque\r\nmalesuada\r\naliquet\r\naliquet."; + var mf = new MeasurementFont() + { + FontFamily = "Archivo Narrow", + Size = 11f, + Style = MeasurementFontStyles.Regular + }; + + //Archivo Narrow is built in default fallback font that may not exists in directories + //It will be found even on "not found" availability + var tEngine = + new Lazy(() => new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + })).Value; + + var tle = tEngine.GetTextLayoutEngineForFont(mf); + + var maxWidth = 54.1420d; + + var wrappedStrings = tle.WrapText(Lorem20Str, mf.Size, maxWidth); + + var savedStrings = savedCompareString.Split("\r\n"); + + List differingStrings = new(); + + if (wrappedStrings.Count() > savedStrings.Count()) + differingStrings = savedStrings.Except(wrappedStrings).ToList(); + else + differingStrings = wrappedStrings.Except(savedStrings).ToList(); + + ////INTENTIONAL COMMENT for easier debugging later. + ////It is sometimes easier to compare files directly when debugging rather than looking through "differingStrings" + //bool writeFiles = true; + + //if (/*differingStrings.Count() > 0*/ writeFiles) + //////{ + //File.WriteAllText("C:\\temp\\LoremIpsum20Free_NEW.txt", string.Join("\r\n", wrappedStrings.ToArray())); + //File.WriteAllText("C:\\temp\\LoremIpsum20Free_OLD.txt", savedCompareString); + + //var currStr = File.ReadAllText("C:\\temp\\LoremIpsum20Free_NEW.txt"); + + //var res = savedCompareString.CompareTo(currStr); + + //Assert.AreEqual(savedCompareString, currStr); + //////} + + Assert.AreEqual(0, differingStrings.Count()); + } + + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Integration/LayoutSystemTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Integration/LayoutSystemTests.cs new file mode 100644 index 0000000000..cfc24d12d4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Integration/LayoutSystemTests.cs @@ -0,0 +1,415 @@ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.Integration.RichText; +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Style; +using System.Drawing; +using static System.Net.Mime.MediaTypeNames; + +namespace EPPlus.Fonts.OpenType.Tests.Integration +{ + [TestClass] + public class LayoutSystemTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void TestParagraphs() + { + + List lstOfRichText = new() { "MyparticularilyLongWord", "WithAbsolutelyNoSpacesAtAllJustToBeDifficult" }; + var font = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + var font2 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var styleRuns = paragraph.GetTextOfAllTextRuns(); + + Assert.AreEqual(lstOfRichText[0], styleRuns[0]); + Assert.AreEqual(lstOfRichText[1], styleRuns[1]); + + + var layout = OpenTypeFonts.GetTextLayoutEngineForFont(font); + var wrappedLines = layout.WrapRichTextLines(fragments, 225d); + + var wrappedLinesPara = paragraph.Wrap(225d); + + Assert.AreEqual(wrappedLines.Count, wrappedLinesPara.Count); + + for (int i = 0; i < wrappedLines.Count; i++) + { + Assert.AreEqual(wrappedLines[i].Text, wrappedLinesPara[i].Text); + Assert.AreEqual(wrappedLines[i].Width, wrappedLinesPara[i].Width); + } + } + + [TestMethod] + public void TestLayoutSystemParagraphChars() + { + List lstOfRichText = new() { "Here comes lorem ipsum\u2029 " + + "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit amet consectetur adipisci[ng] velit, sed quia non numquam [do] eius modi tempora inci[di]dunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum[d] exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? [D]Quis autem vel eum i[r]ure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?\u2029 " + + "At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem reru[d]um facilis est e[r]t expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellend[a]us. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.\u2029 " + + "Let's see if we can recognize unicode paragraph separators" }; + var font = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Bold + }; + var fragments = new List() + { + new TextFragment() {Text = lstOfRichText[0], Font = font } + }; + + var layout = new LayoutSystem(SystemFontsEngine, fragments); + Assert.AreEqual(3, layout.GetParagraphSeparatorCount()); + } + + [TestMethod] + public void TestParagraphs_DifficultCase() + { + List lstOfRichText = new() { "TextBox2", "ra underline", "La Strike", "Goudy size 16" }; + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + List fonts = new() { font2, font3, font4, font5 }; + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i]}; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var wrappedLines = paragraph.Wrap(225d); + + var line1 = wrappedLines[0]; + } + + [TestMethod] + public void EnsureCorrectTotalIndex() + { + List lstOfRichText = new() { "aaaaaaaa aa aaaaaaaaaLa Strike", "Goudy size 16" }; + var font = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + var font2 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var wrappedLines = paragraph.Wrap(225d); + + Assert.AreEqual("StrikeGoudy size", wrappedLines[1].Text); + Assert.AreEqual(24, wrappedLines[1].LineFragments[0].StartFullTextIdx); + Assert.AreEqual(24, wrappedLines[1].LineFragments[0].StartRtIdx); + } + + [TestMethod] + public void EnsureRTCharIdxBecomesCorrectWhenBreaking() + { + List lstOfRichText = new() { "MyparticularilyLongWord", "WithAbsolutelyNoSpacesAtAllJustToBeDifficult" }; + var font = new MeasurementFont() + { + FontFamily = "Archivo Narrow", + Size = 12, + Style = MeasurementFontStyles.Regular + }; + var font2 = new MeasurementFont() + { + FontFamily = "Oi", + Size = 20, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var shaper = TestFolderEngine.GetShaperForFont(font2); + //var shapes = shaper.ShapeLight("WithAbsolutelyNoSpacesAtAllJustToBeDifficult"); + var layout = new TextLayoutEngine(TestFolderEngine, shaper); + var wrappedLines = layout.WrapRichTextLines(fragments, 225d); + + var paragraph = new LayoutSystem(TestFolderEngine, fragments); + var wrappedLines2 = paragraph.Wrap(225d); + //var layout = OpenTypeFonts.GetTextLayoutEngineForFont(font, FontFolders); + //var wrappedLines = layout.WrapRichTextLines(fragments, 225d); + + Assert.AreEqual(5, wrappedLines[1].LineFragments[0].StartRtIdx); + Assert.AreEqual(17, wrappedLines[2].LineFragments[0].StartRtIdx); + Assert.AreEqual(29, wrappedLines[3].LineFragments[0].StartRtIdx); + Assert.AreEqual(41, wrappedLines[4].LineFragments[0].StartRtIdx); + + Assert.AreEqual(5, wrappedLines2[1].LineFragments[0].StartRtIdx); + Assert.AreEqual(17, wrappedLines2[2].LineFragments[0].StartRtIdx); + Assert.AreEqual(29, wrappedLines2[3].LineFragments[0].StartRtIdx); + Assert.AreEqual(41, wrappedLines2[4].LineFragments[0].StartRtIdx); + } + + + [TestMethod] + public void EnsureWrappingSimplePlainTextCorrectly() + { + string myText = "Hi! I am a simple but somewhat wordy text string that is being Tested for wrapping in the case where only one font exists"; + var font = new MeasurementFont() + { + FontFamily = "Archivo Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font }; + List strings = new List() { myText }; + + + var fragments = new List(); + + for (int i = 0; i < strings.Count(); i++) + { + var currentFrag = new TextFragment() { Text = strings[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var paragraph = new LayoutSystem(TestFolderEngine, fragments); + + var lines = paragraph.Wrap(92.976377953d); + + Assert.AreEqual("Hi! I am a simple but", lines[0].Text); + Assert.AreEqual("somewhat wordy text", lines[1].Text); + Assert.AreEqual("string that is being", lines[2].Text); + Assert.AreEqual("Tested for wrapping in", lines[3].Text); + Assert.AreEqual("the case where only", lines[4].Text); + Assert.AreEqual("one font exists", lines[5].Text); + } + + [TestMethod] + public void EnsureWrappingRichTextAndGettingLineSpacing() + { + List txtLst = new List() { "Hi ", "I am rich ", "But I am Even Richer " }; + var rt = new RichTextFormatBase(txtLst[0], "Roboto", 12f); + var rtSecond = new RichTextFormatBase(txtLst[1], "Archivo Narrow", 11f); + var rtThird = new RichTextFormatBase(txtLst[2], "Roboto", 18f); + + rtThird.Italic = true; + rtThird.Bold = true; + + List rtLst = new List() { rt, rtSecond, rtThird}; + + var paragraph = new LayoutSystem(TestFolderEngine, rtLst); + + var lines = paragraph.Wrap(92.976377953d); + + //Assert correct wrapping + Assert.AreEqual("Hi I am rich But I", lines[0].Text); + Assert.AreEqual("am Even", lines[1].Text); + Assert.AreEqual("Richer", lines[2].Text); + + //Assert line segments correct count + Assert.AreEqual(3, lines[0].LineFragments.Count); + Assert.AreEqual(3, lines[0].InternalLineFragments.Count); + Assert.AreEqual(1, lines[1].LineFragments.Count); + Assert.AreEqual(1, lines[1].InternalLineFragments.Count); + Assert.AreEqual(1, lines[2].LineFragments.Count); + Assert.AreEqual(1, lines[2].InternalLineFragments.Count); + + //Assert correct fragment in correct spot + Assert.AreEqual(rtLst[0], (IRichTextFormatEssential)lines[0].LineFragments[0].OriginalTextFragment.RichTextOptions); + Assert.AreEqual(rtLst[1], (IRichTextFormatEssential)lines[0].LineFragments[1].OriginalTextFragment.RichTextOptions); + Assert.AreEqual(rtLst[2], (IRichTextFormatEssential)lines[0].LineFragments[2].OriginalTextFragment.RichTextOptions); + + Assert.AreEqual(rtLst[2], (IRichTextFormatEssential)lines[1].LineFragments[0].OriginalTextFragment.RichTextOptions); + Assert.AreEqual(rtLst[2], (IRichTextFormatEssential)lines[2].LineFragments[0].OriginalTextFragment.RichTextOptions); + } + + [TestMethod] + public void TestGetSection() + { + List txtLst = new List() { "Hi ", "I am rich ", "But I am Even Richer " }; + var rt = new RichTextFormatBase(txtLst[0], "Roboto", 12f); + var rtSecond = new RichTextFormatBase(txtLst[1], "Archivo Narrow", 11f); + var rtThird = new RichTextFormatBase(txtLst[2], "Roboto", 18f); + + rtThird.Italic = true; + rtThird.Bold = true; + + List rtLst = new List() { rt, rtSecond, rtThird }; + + var paragraph = new LayoutSystem(TestFolderEngine, rtLst); + + var fulltext = paragraph.GetTextOfAllTextRuns(); + + var joinedInput = string.Join("", txtLst.ToArray()); + var joinedOutput = string.Join("", fulltext.ToArray()); + + Assert.AreEqual(joinedInput, joinedOutput); + + paragraph.Wrap(92.976377953d); + } + + [TestMethod] + public void TestGetSectionWithIndividualChars() + { + List txtLst = new List() { "A", "B", "C", "D" }; + var rt = new RichTextFormatBase(txtLst[0], "Roboto", 12f); + var rtSecond = new RichTextFormatBase(txtLst[1], "Archivo Narrow", 11f); + var rtThird = new RichTextFormatBase(txtLst[2], "Roboto", 18f); + var rtFourth = new RichTextFormatBase(txtLst[3], "Archivo Narrow", 18f); + + + List rtLst = new List() { rt, rtSecond, rtThird, rtFourth }; + + var pIndividual = new LayoutSystem(TestFolderEngine, rtLst); + + var joinedInput = string.Join("", txtLst.ToArray()); + var joinedOutput = string.Join("", pIndividual.GetTextOfAllTextRuns().ToArray()); + + + Assert.AreEqual(joinedInput, joinedOutput); + } + + [TestMethod] + public void TestGetSectionMixed() + { + var txtLstMixed = new List() { "Abc", "D", "Efg", "H" }; + var rt = new RichTextFormatBase(txtLstMixed[0], "Roboto", 12f); + var rtSecond = new RichTextFormatBase(txtLstMixed[1], "Archivo Narrow", 11f); + var rtThird = new RichTextFormatBase(txtLstMixed[2], "Roboto", 18f); + var rtFourth = new RichTextFormatBase(txtLstMixed[3], "Archivo Narrow", 18f); + + var rtLstMixed = new List() { rt, rtSecond, rtThird, rtFourth }; + var pMixed = new LayoutSystem(TestFolderEngine, rtLstMixed); + + var InMix = string.Join("", txtLstMixed.ToArray()); + var OutMix = string.Join("", pMixed.GetTextOfAllTextRuns().ToArray()); + + Assert.AreEqual(InMix, OutMix); + } + + [TestMethod] + public void TestGetSectionNumber2() + { + var txtLstMixed = new List() { "10"}; + var rt = new RichTextFormatBase(txtLstMixed[0], "Roboto", 12f); + + var rtLstMixed = new List() { rt }; + var pMixed = new LayoutSystem(TestFolderEngine, rtLstMixed); + + var InMix = string.Join("", txtLstMixed.ToArray()); + var OutMix = string.Join("", pMixed.GetTextOfAllTextRuns().ToArray()); + + var wrappedLines = pMixed.Wrap(60d); + + Assert.AreEqual(InMix, OutMix); + } + + [TestMethod] + public void TestLayoutSystemMultipleParagraphs() + { + var paragraphEndSymbol = '\u2029'; + + List lstOfRichText = new() { $"Here comes lorem ipsum{paragraphEndSymbol} " + + $"Sed ut perspiciatis,{paragraphEndSymbol}", $"u{paragraphEndSymbol}n{paragraphEndSymbol}de{paragraphEndSymbol} omnis" }; + var font = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Bold + }; + + var font2 = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Italic + }; + + var fragments = new List() + { + new TextFragment() {Text = lstOfRichText[0], Font = font }, + new TextFragment() {Text = lstOfRichText[1], Font = font2 } + }; + + var layout = new LayoutSystem(SystemFontsEngine, fragments); + Assert.AreEqual(5, layout.GetParagraphSeparatorCount()); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Integration/MeasurerComparisonTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Integration/MeasurerComparisonTests.cs new file mode 100644 index 0000000000..5b078c3eac --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Integration/MeasurerComparisonTests.cs @@ -0,0 +1,396 @@ +//using EPPlus.Fonts.OpenType.Integration; +//using EPPlus.Fonts.OpenType.TextShaping; +//using EPPlus.Fonts.OpenType.TrueTypeMeasurer; +//using EPPlus.Fonts.OpenType.Utils; +//using Microsoft.VisualStudio.TestTools.UnitTesting; +//using OfficeOpenXml.Interfaces.Drawing.Text; +//using OfficeOpenXml.Interfaces.Fonts; +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; +//using IntegrationTextFragment = EPPlus.Fonts.OpenType.Integration.TextFragment; +//using TrueTypeTextFragment = EPPlus.Fonts.OpenType.TrueTypeMeasurer.TextFragment; + +//namespace EPPlus.Fonts.OpenType.Tests.Integration +//{ +// [TestClass] +// public class MeasurerComparisonTests : FontTestBase +// { +// public override TestContext? TestContext { get; set; } + +// #region Single Text Measurement Comparison + +// [TestMethod] +// public void Compare_MeasureSimpleText_ShouldBeClose() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// // Old measurer +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); + +// // New measurer +// var shaper = new TextShaper(font); +// var newMeasurer = new OpenTypeFontTextMeasurer(shaper); + +// var measurementFont = new MeasurementFont +// { +// FontFamily = "Roboto", +// Size = 11 +// }; + +// // Act +// var oldResult = oldMeasurer.MeasureText("Hello World", measurementFont); +// var newResult = newMeasurer.MeasureText("Hello World", measurementFont); + +// // Assert +// Debug.WriteLine($"Old Width: {oldResult.Width}, New Width: {newResult.Width}"); +// Debug.WriteLine($"Old Height: {oldResult.Height}, New Height: {newResult.Height}"); +// Debug.WriteLine($"Old FontHeight: {oldResult.FontHeight}, New FontHeight: {newResult.FontHeight}"); + +// // Allow small tolerance for rounding differences +// double tolerance = 0.5; // points +// Assert.AreEqual(oldResult.Width, newResult.Width, tolerance, +// $"Width difference too large. Old: {oldResult.Width}, New: {newResult.Width}"); +// Assert.AreEqual(oldResult.Height, newResult.Height, tolerance, +// $"Height difference too large. Old: {oldResult.Height}, New: {newResult.Height}"); +// } + +// [TestMethod] +// public void Compare_MeasureTextWithKerning_ShouldBeClose() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); + +// var shaper = new TextShaper(font); +// var newMeasurer = new OpenTypeFontTextMeasurer(shaper); + +// var measurementFont = new MeasurementFont +// { +// FontFamily = "Roboto", +// Size = 11 +// }; + +// // Act - "AV" has kerning +// var oldResult = oldMeasurer.MeasureText("AV", measurementFont); +// var newResult = newMeasurer.MeasureText("AV", measurementFont); + +// // Assert +// Debug.WriteLine($"Old Width: {oldResult.Width}, New Width: {newResult.Width}"); + +// double tolerance = 0.5; +// Assert.AreEqual(oldResult.Width, newResult.Width, tolerance, +// $"Kerned text width differs. Old: {oldResult.Width}, New: {newResult.Width}"); +// } + +// [TestMethod] +// public void Compare_MeasureMultiLineText_NewImplementationFixesBugs() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// oldMeasurer.MeasureWrappedTextCells = true; + +// var shaper = new TextShaper(font); +// var newMeasurer = new OpenTypeFontTextMeasurer(shaper); +// newMeasurer.MeasureWrappedTextCells = true; + +// var measurementFont = new MeasurementFont +// { +// FontFamily = "Roboto", +// Size = 11 +// }; + +// string multiLineText = "Line 1\r\nLine 2\nLine 3"; + +// // Act +// var oldResult = oldMeasurer.MeasureText(multiLineText, measurementFont); +// var newResult = newMeasurer.MeasureText(multiLineText, measurementFont); + +// // Measure each line individually for verification +// var lines = multiLineText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); +// float expectedMaxWidth = 0; +// foreach (var line in lines) +// { +// var lineResult = newMeasurer.MeasureText(line, measurementFont); +// expectedMaxWidth = Math.Max(expectedMaxWidth, lineResult.Width); +// Debug.WriteLine($"Line '{line}': {lineResult.Width}"); +// } + +// double expectedHeight = shaper.GetLineHeightInPoints(11.0f) * lines.Length; + +// // Assert +// Debug.WriteLine(""); +// Debug.WriteLine($"Expected max width (widest line): {expectedMaxWidth}"); +// Debug.WriteLine($"Old Width: {oldResult.Width} (BUG: incorrect due to line break handling)"); +// Debug.WriteLine($"New Width: {newResult.Width} (CORRECT: max of individual lines)"); +// Debug.WriteLine(""); +// Debug.WriteLine($"Expected total height ({lines.Length} lines): {expectedHeight}"); +// Debug.WriteLine($"Old Height: {oldResult.Height} (BUG: returns single line height)"); +// Debug.WriteLine($"New Height: {newResult.Height} (CORRECT: total height)"); + +// // Verify new implementation is correct +// Assert.AreEqual(expectedMaxWidth, newResult.Width, 0.1, +// "New measurer correctly returns max width of all lines"); + +// Assert.AreEqual(expectedHeight, newResult.Height, 0.1, +// "New measurer correctly returns total height"); + +// // Document that old implementation has bugs +// Debug.WriteLine(""); +// Debug.WriteLine("DOCUMENTED BUGS in old FontMeasurerTrueType.MeasureText:"); +// Debug.WriteLine(" 1. Width calculation incorrect for multi-line text"); +// Debug.WriteLine($" - Old returns {oldResult.Width:F2} instead of correct {expectedMaxWidth:F2}"); +// Debug.WriteLine(" 2. Height returns single line instead of total"); +// Debug.WriteLine($" - Old returns {oldResult.Height:F2} instead of correct {expectedHeight:F2}"); +// Debug.WriteLine(""); +// Debug.WriteLine("✅ New OpenTypeFontTextMeasurer fixes both bugs"); +// } + +// #endregion + +// #region Font Metrics Comparison + +// [TestMethod] +// public void Compare_GetSingleLineSpacing_ShouldMatch() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); + +// // Act +// var oldSpacing = oldMeasurer.GetSingleLineSpacing(); +// var newSpacing = shaper.GetLineHeightInPoints(11.0f); + +// // Assert +// Debug.WriteLine($"Old Spacing: {oldSpacing}, New Spacing: {newSpacing}"); + +// double tolerance = 0.1; +// Assert.AreEqual(oldSpacing, newSpacing, tolerance, +// $"Line spacing differs. Old: {oldSpacing}, New: {newSpacing}"); +// } + +// [TestMethod] +// public void Compare_GetBaseLine_ShouldMatch() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); + +// // Act +// var oldBaseline = oldMeasurer.GetBaseLine(); +// var newBaseline = shaper.GetAscentInPoints(11.0f); + +// // Assert +// Debug.WriteLine($"Old Baseline: {oldBaseline}, New Baseline: {newBaseline}"); + +// double tolerance = 0.1; +// Assert.AreEqual(oldBaseline, newBaseline, tolerance, +// $"Baseline differs. Old: {oldBaseline}, New: {newBaseline}"); +// } + +// #endregion + +// #region Text Wrapping Comparison + +// [TestMethod] +// public void Compare_WrapSimpleText_ShouldGiveSameLines() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); + +// var shaper = new TextShaper(font); +// var layout = new TextLayoutEngine(shaper); + +// var measurementFont = new MeasurementFont +// { +// FontFamily = "Roboto", +// Size = 11 +// }; + +// string text = "This is a long text that should wrap at some point"; +// double maxWidth = 100; // pixels + +// // Act +// var oldLines = oldMeasurer.MeasureAndWrapText(text, measurementFont, maxWidth); +// var newLines = layout.WrapText(text, 11f, maxWidth.PixelToPoint()); + +// // Assert +// Debug.WriteLine($"Old line count: {oldLines.Count}, New line count: {newLines.Count}"); +// for (int i = 0; i < Math.Max(oldLines.Count, newLines.Count); i++) +// { +// var oldLine = i < oldLines.Count ? oldLines[i] : "(none)"; +// var newLine = i < newLines.Count ? newLines[i] : "(none)"; +// Debug.WriteLine($"Line {i}: Old='{oldLine}', New='{newLine}'"); +// } + +// Assert.AreEqual(oldLines.Count, newLines.Count, +// "Number of wrapped lines should match"); + +// for (int i = 0; i < oldLines.Count; i++) +// { +// Assert.AreEqual(oldLines[i], newLines[i], +// $"Line {i} content differs. Old: '{oldLines[i]}', New: '{newLines[i]}'"); +// } +// } + +// [TestMethod] +// public void Compare_WrapTextWithPreExistingWidth_ShouldGiveSameLines() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); +// var layout = new TextLayoutEngine(shaper); + +// var measurementFont = new MeasurementFont +// { +// FontFamily = "Roboto", +// Size = 11 +// }; + +// string text = "continuation text that wraps"; +// double maxWidth = 150; // pixels +// double preExistingWidth = 50; // pixels + +// // Act +// var oldLines = oldMeasurer.MeasureAndWrapText(text, measurementFont, maxWidth, preExistingWidth); +// var newLines = layout.WrapText(text, 11f, maxWidth.PixelToPoint(), preExistingWidth.PixelToPoint()); + +// // Assert +// Debug.WriteLine($"Old line count: {oldLines.Count}, New line count: {newLines.Count}"); +// for (int i = 0; i < Math.Max(oldLines.Count, newLines.Count); i++) +// { +// var oldLine = i < oldLines.Count ? oldLines[i] : "(none)"; +// var newLine = i < newLines.Count ? newLines[i] : "(none)"; +// Debug.WriteLine($"Line {i}: Old='{oldLine}', New='{newLine}'"); +// } + +// Assert.AreEqual(oldLines.Count, newLines.Count, +// "Number of wrapped lines should match with pre-existing width"); +// } + +// #endregion + +// #region Rich Text Wrapping Comparison + +// [TestMethod] +// public void Compare_WrapRichText_ShouldGiveSimilarLines() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); +// var layout = new TextLayoutEngine(shaper, FontFolders); + +// var textFragments = new List { "Hello ", "world ", "from ", "rich ", "text" }; +// var fonts = new List +// { +// new MeasurementFont { FontFamily = "Roboto", Size = 11 }, +// new MeasurementFont { FontFamily = "Roboto", Size = 12, Style = MeasurementFontStyles.Bold }, +// new MeasurementFont { FontFamily = "Roboto", Size = 11 }, +// new MeasurementFont { FontFamily = "Roboto", Size = 11, Style = MeasurementFontStyles.Italic }, +// new MeasurementFont { FontFamily = "Roboto", Size = 11 } +// }; + +// // New API uses IntegrationTextFragment +// var fragments = new List(); +// for (int i = 0; i < textFragments.Count; i++) +// { +// fragments.Add(new IntegrationTextFragment +// { +// Text = textFragments[i], +// Font = fonts[i] +// }); +// } + +// double maxWidth = 100; // points + +// // Act +// var oldLines = oldMeasurer.WrapMultipleTextFragments(textFragments, fonts, maxWidth); +// var newLines = layout.WrapRichText(fragments, maxWidth); + +// // Assert +// Debug.WriteLine($"Old line count: {oldLines.Count}, New line count: {newLines.Count}"); +// for (int i = 0; i < Math.Max(oldLines.Count, newLines.Count); i++) +// { +// var oldLine = i < oldLines.Count ? oldLines[i] : "(none)"; +// var newLine = i < newLines.Count ? newLines[i] : "(none)"; +// Debug.WriteLine($"Line {i}: Old='{oldLine}', New='{newLine}'"); +// } + +// // Note: May not match exactly due to improved shaping/kerning +// // But should be close +// Assert.IsTrue(Math.Abs(oldLines.Count - newLines.Count) <= 1, +// $"Line count should be similar. Old: {oldLines.Count}, New: {newLines.Count}"); +// } + +// #endregion + +// #region Edge Cases Comparison + +// [TestMethod] +// public void Compare_EmptyString_BothShouldReturnZero() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); +// var newMeasurer = new OpenTypeFontTextMeasurer(shaper); + +// var measurementFont = new MeasurementFont { FontFamily = "Roboto", Size = 11 }; + +// // Act +// var oldResult = oldMeasurer.MeasureText("", measurementFont); +// var newResult = newMeasurer.MeasureText("", measurementFont); + +// // Assert +// Debug.WriteLine($"Old result: Width={oldResult.Width}, Height={oldResult.Height}"); +// Debug.WriteLine($"New result: Width={newResult.Width}, Height={newResult.Height}"); + +// // Both should return 0 width for empty string +// Assert.AreEqual(0f, oldResult.Width, "Old measurer: Empty string should have 0 width"); +// Assert.AreEqual(0f, newResult.Width, "New measurer: Empty string should have 0 width"); + +// // Note: Old measurer returns font height, new returns 0 (both reasonable) +// Debug.WriteLine($"Height difference: Old returns font height ({oldResult.Height}), New returns 0 ({newResult.Height})"); +// } + +// [TestMethod] +// public void Compare_SingleCharacter_ShouldMatch() +// { +// // Arrange +// var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + +// var oldMeasurer = new FontMeasurerTrueType(11f, "Roboto", FontSubFamily.Regular); +// var shaper = new TextShaper(font); +// var newMeasurer = new OpenTypeFontTextMeasurer(shaper); + +// var measurementFont = new MeasurementFont { FontFamily = "Roboto", Size = 11 }; + +// // Act +// var oldResult = oldMeasurer.MeasureText("A", measurementFont); +// var newResult = newMeasurer.MeasureText("A", measurementFont); + +// // Assert +// Debug.WriteLine($"Old Width: {oldResult.Width}, New Width: {newResult.Width}"); + +// double tolerance = 0.5; +// Assert.AreEqual(oldResult.Width, newResult.Width, tolerance); +// } + +// #endregion +// } +//} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Integration/TextLayoutEngineTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Integration/TextLayoutEngineTests.cs new file mode 100644 index 0000000000..039e2a368f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Integration/TextLayoutEngineTests.cs @@ -0,0 +1,1269 @@ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.RichText; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Tests.Integration +{ + [TestClass] + public class TextLayoutEngineTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + + #region Single-Font Wrapping Tests + + [TestMethod] + public void WrapText_ShortText_NoWrapping() + { + RequireFont(SystemFontsEngine, "Calibri"); + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Act + var lines = layout.WrapText("Hello", 11f, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("Hello", lines[0]); + } + + [TestMethod] + public void WrapText_LongText_WrapsAtSpaces() + { + RequireFont(SystemFontsEngine, "Calibri"); + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Act - narrow width forces wrapping + var lines = layout.WrapText("Hello world test", 11f, 50); + + // Assert + Assert.IsTrue(lines.Count > 1, "Text should wrap to multiple lines"); + + // Each line should be a complete word (no mid-word breaks) + foreach (var line in lines) + { + Assert.IsFalse(string.IsNullOrEmpty(line)); + } + } + + [TestMethod] + public void WrapText_WithLineBreaks_PreservesBreaks() + { + RequireFont(SystemFontsEngine, "Calibri"); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Act + var lines = layout.WrapText("Line 1\r\nLine 2\nLine 3", 11f, 1000); + + // Assert + Assert.AreEqual(3, lines.Count); + Assert.AreEqual("Line 1", lines[0]); + Assert.AreEqual("Line 2", lines[1]); + Assert.AreEqual("Line 3", lines[2]); + } + + [TestMethod] + public void WrapText_TestWhenOnExactWrapPlusSpaces2() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + //'sit amet non' is EXACTLY 72 pixels (54 points) in excel at 100% size/display + //So an added space should push 'non' over the edge to the next line + var text = "sit amet non lacus."; + var comparison = new List() {"sit amet", "non lacus."}; + + var maxWidthPoints = 54d; + + ITextShaper shaper = SystemFontsEngine.GetTextShaper("Aptos Narrow"); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapText( + text, + 11f, + maxWidthPoints, + ShapingOptions.Full + ); + + Assert.IsTrue(comparison.SequenceEqual(wrappedLines)); + } + + [TestMethod] + public void WrapText_TestWhenOnExactWrap() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + //'sit amet non' is EXACTLY 72 pixels (54 points) in excel at 100% size/display + var text = "nulla efficitur commodo sit amet non lacus. Proin viverra enim"; + var comparison = new List() { "nulla", "efficitur", "commodo", "sit amet non", "lacus. Proin", "viverra enim" }; + + ITextShaper shaper = SystemFontsEngine.GetTextShaper("Aptos Narrow"); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapText( + text, + 11f, + 54, + ShapingOptions.Full + ); + + Assert.IsTrue(comparison.SequenceEqual(wrappedLines)); + } + + [TestMethod] + public void WrapText_TestFragments() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var Lorem20Str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pulvinar interdum imperdiet. Praesent ut auctor urna. Phasellus sollicitudin quam vitae est convallis, eu mattis lorem efficitur. Mauris nulla libero, tincidunt id ipsum non, lobortis tristique mauris. Donec ut enim sed enim fermentum molestie vel quis odio. Morbi a fermentum massa, sit amet ultrices est. Aenean ante mi, fermentum nec rhoncus et, vulputate vel sapien. Donec tempus, leo quis luctus rhoncus, augue odio pharetra libero, ac blandit urna turpis sed diam. Vivamus augue purus, eleifend et justo facilisis, imperdiet rhoncus sem. Quisque accumsan pellentesque elit, eget finibus massa accumsan in. Fusce eu accumsan enim. Cras pulvinar enim vel tellus lacinia, consectetur euismod tortor consectetur. Praesent tincidunt pretium eros, ac auctor magna luctus sed. Ut porta lectus quam, non ornare mauris lacinia sit amet. Nullam egestas dolor quis magna porttitor, ac iaculis nisi hendrerit. Proin at mollis lacus, in porttitor nunc. Aliquam erat volutpat. Sed vel egestas risus, at aliquam arcu. Vestibulum quis lobortis nulla. Etiam pellentesque auctor nulla, eget tincidunt felis rhoncus id. Sed metus ante, efficitur id dui eu, fermentum mollis odio. Phasellus ullamcorper iaculis augue vel consequat. Etiam fringilla euismod interdum. Ut molestie massa id fringilla lobortis. Vestibulum malesuada, ante vel mattis ultrices, sem ante molestie augue, non tristique dui mi non nibh. Maecenas dictum, sem eget convallis rhoncus, lacus enim porta neque, in posuere dui ex a sapien. Nam lacus nibh, posuere sed elit eget, condimentum facilisis ligula. Cras consectetur lacus ullamcorper velit aliquet bibendum eget vel nulla. Aenean varius ac erat quis ullamcorper. Donec laoreet arcu a lorem volutpat faucibus. Vivamus vehicula leo ut erat luctus scelerisque. Morbi posuere ex et magna egestas facilisis. Fusce scelerisque volutpat erat bibendum hendrerit. Nam blandit mi ut metus pulvinar, vel tempus lacus euismod. Quisque imperdiet sit amet sapien sed ultricies. Phasellus sodales, ipsum vitae tincidunt facilisis, nulla ligula faucibus felis, eget vehicula ante lacus eu lorem. Integer congue diam ac viverra tristique. Curabitur tristique dolor quis quam pretium, et scelerisque quam dictum. Maecenas vitae sodales ligula. Pellentesque maximus diam vel porta convallis. Ut aliquam eros quis porta pellentesque. Fusce in ex ut mi egestas cursus. Aliquam erat volutpat. Cras laoreet condimentum laoreet. Sed eget facilisis tellus. Morbi viverra odio sed odio placerat mollis. Duis turpis metus, dignissim varius urna quis, viverra dignissim dui. Vivamus viverra at nisi quis convallis. Suspendisse fringilla risus et ante sollicitudin, sed eleifend sem placerat. Proin pretium blandit arcu, eget rhoncus risus hendrerit at. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus vulputate efficitur maximus. Cras blandit nulla eu nisi auctor tempus. Sed pretium lacus ac magna vestibulum, aliquam faucibus orci luctus. Mauris enim lorem, varius ut ante quis, varius viverra lectus. Fusce blandit nibh vel feugiat efficitur. Donec maximus id justo ac mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla placerat lectus et purus dictum, id congue nisi euismod. Maecenas euismod fermentum diam, sit amet gravida magna suscipit a. Quisque consectetur arcu eu nunc sodales scelerisque. Nulla non tincidunt nulla. Pellentesque ut tortor vel enim convallis malesuada. Aliquam ultricies bibendum ultrices. Mauris rutrum ac nisl vel luctus. Donec quis nibh vitae orci ultricies gravida. Aliquam vitae velit porttitor lorem bibendum fringilla volutpat a eros. Curabitur at commodo tortor. Etiam ultricies, neque et iaculis euismod, diam ligula luctus mi, vitae lobortis felis lorem eu nulla. Sed a semper ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla mauris elit, pulvinar ac tortor et, luctus hendrerit nisl. In egestas auctor urna vitae laoreet. Praesent bibendum egestas convallis. Proin non suscipit tellus. Nullam at nibh in urna laoreet sodales non vel tellus. Donec in enim dui. Phasellus quis quam tincidunt, pellentesque lorem ac, scelerisque neque. Integer nec tempus urna. Donec elit massa, eleifend eu sapien sit amet, mollis pellentesque est. Nullam tristique tellus iaculis arcu consectetur pretium. Sed venenatis convallis scelerisque. Suspendisse varius urna sit amet purus accumsan, id ultricies erat efficitur. Cras non ipsum eget nulla efficitur commodo sit amet non lacus. Proin viverra enim sit amet enim tempus ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac massa interdum, gravida ex egestas, finibus purus. Nunc consectetur commodo lacus, ac convallis quam lobortis eu. Sed convallis tempor commodo. Nulla sed convallis mauris. Donec venenatis nisi est, ac ullamcorper mi pretium quis. Donec vitae eros at ipsum interdum scelerisque nec vitae nisi. Sed vestibulum erat ac bibendum dapibus. Morbi nec elit id quam tristique cursus id sed sem. Praesent non ante enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent non mauris dui. Aliquam rhoncus mattis ante sed venenatis. Vivamus vehicula sed sapien sed dictum. In aliquet, urna efficitur tincidunt lobortis, nibh justo tristique purus, sed volutpat risus magna et libero.Suspendisse lectus justo, varius eget arcu et, semper laoreet erat. Quisque eget lacus ornare, pellentesque erat sit amet, vulputate felis. Duis luctus, massa a pellentesque mollis, massa elit convallis mi, vel bibendum ex ex eu purus. Suspendisse vel fermentum urna, ac commodo enim. Mauris tincidunt cursus elit, a volutpat libero commodo et. Etiam dapibus libero venenatis tellus lobortis, vel lacinia elit faucibus. Maecenas semper sed quam quis finibus. Integer efficitur, libero imperdiet sollicitudin commodo, elit arcu vulputate est, eget finibus mi urna sit amet magna. Cras ullamcorper consequat ornare. Fusce convallis nunc vel risus cursus, at maximus ligula cursus. Pellentesque vulputate risus libero, eget cursus nibh sodales sed. Donec accumsan sem et massa semper, id dignissim velit vehicula.Cras cursus ipsum ac erat vehicula, nec iaculis purus dictum. Quisque lacinia elit vitae leo dictum, vel dignissim velit dapibus. Aenean sem nisi, faucibus interdum justo eu, euismod porttitor ex. Morbi et lectus lectus. Duis neque felis, suscipit at scelerisque eu, scelerisque id orci. Curabitur et placerat ipsum. Proin gravida sapien nisl, et varius ipsum mollis nec. Quisque dignissim consectetur feugiat. Aenean eros purus, laoreet interdum rutrum at, aliquet sit amet lectus. Donec gravida lorem ut tincidunt laoreet. Donec consequat viverra ligula, in accumsan mi bibendum scelerisque. Quisque ac risus justo. Morbi magna arcu, egestas nec luctus commodo, cursus eget nunc. Vivamus euismod lorem ex, et maximus felis hendrerit eget. Nullam ullamcorper euismod ligula, et iaculis ligula ultricies a. Fusce aliquam, enim vel fermentum ultrices, elit quam semper erat, vitae semper velit augue non magna.Quisque maximus semper arcu, id pellentesque est tempus a. Phasellus lacus elit, auctor sit amet lacinia a, dapibus vitae velit. Phasellus ut pharetra justo, ut ultricies erat. Sed molestie sapien vel interdum lobortis. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla nec mauris quis nisi vulputate gravida quis nec velit.Nam et congue ipsum. Nulla vel elit non dolor mollis aliquet vel at magna. Pellentesque nec facilisis elit. In vulputate quis sem porta suscipit. Nullam sed ex ornare nibh suscipit mattis quis non lacus. Mauris vel ex urna. Vivamus ultricies sapien sit amet sapien vehicula gravida. Donec feugiat volutpat quam. Vestibulum auctor dictum nisl, id hendrerit metus ullamcorper sed. Nulla maximus lacus vel mollis maximus. Nulla laoreet placerat quam eu viverra. Etiam feugiat accumsan nisl a condimentum. Sed ultricies ante ante, ac auctor ligula gravida nec. Praesent a neque dignissim, sagittis felis sit amet, condimentum turpis. Fusce at leo vel est blandit malesuada. Pellentesque et neque non metus pellentesque imperdiet. Praesent pellentesque lacinia lorem, et tristique tellus efficitur id. Suspendisse aliquet ultricies justo vitae interdum. Cras tristique viverra quam, eget gravida mi fermentum imperdiet. Sed imperdiet vitae purus ut volutpat. Nulla lacinia elit in fermentum consectetur. Phasellus commodo ut nisl sit amet sagittis. Duis ac ornare orci. Vivamus vel enim posuere, pharetra ex vel, elementum est. Vestibulum commodo luctus metus eget maximus. Suspendisse a nulla a odio eleifend faucibus. Suspendisse semper lacus non porttitor aliquet. Cras ac scelerisque magna, et pulvinar justo. Integer cursus pulvinar fringilla. Mauris imperdiet nibh sit amet tempor laoreet. Morbi tincidunt tortor ex, sit amet maximus purus tristique quis. Quisque sed hendrerit velit. Mauris mattis nibh ut eros luctus, eget mattis massa auctor. Phasellus eu neque at augue gravida sagittis nec non tortor. Etiam porttitor sem sodales mi ullamcorper gravida. In in dictum orci. In vitae vestibulum quam. Cras augue eros, tincidunt ac elit posuere, sollicitudin efficitur lectus. Praesent quis sodales nisl. Proin sit amet molestie est. In commodo mauris vel mauris efficitur, nec mollis mauris sagittis. Cras ligula nibh, egestas sit amet eros in, lacinia tristique magna. Cras risus libero, lacinia eget libero vitae, maximus aliquet nibh. Mauris id sodales purus, vitae dictum lectus. Cras consectetur ligula velit, tempus pulvinar lacus porttitor vitae. Phasellus eget tellus ipsum. Donec interdum laoreet elit non vestibulum. Cras sed urna ullamcorper, aliquam erat eget, porta orci. Vestibulum eget congue nulla. Sed sem tortor, euismod at rutrum id, sagittis a nunc. Duis in nibh facilisis, dignissim purus ut, hendrerit magna. Sed semper ligula id massa elementum, non malesuada velit egestas. Nullam dictum, mi nec euismod sagittis, ligula leo ullamcorper dolor, quis faucibus odio metus eget magna. Ut gravida metus non metus bibendum bibendum. In sagittis eleifend aliquet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam mollis sagittis felis, in faucibus tortor pretium vel. Nam nec enim metus. Donec in augue arcu. Proin non lobortis purus, sit amet lacinia elit. Suspendisse quis eros condimentum, blandit justo sit amet, lobortis nisl. Suspendisse maximus massa sed urna tempor ornare. Nunc malesuada purus odio, eu luctus lectus auctor nec. Morbi auctor pellentesque auctor. Sed ullamcorper, ex vitae aliquam vulputate, est diam feugiat mi, id porttitor lectus orci ac leo. Donec sit amet velit pulvinar, venenatis turpis ut, interdum ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum eu lacus urna. Maecenas sem nulla, accumsan eu ultricies sed, tempor vel magna. Cras aliquet sollicitudin sapien ac pulvinar. Praesent ac sodales mi. Integer vitae mauris massa. Maecenas iaculis orci et faucibus interdum. Nunc nec maximus felis, sed finibus quam. Pellentesque felis massa, vestibulum in tellus vitae, congue tincidunt justo. Nunc vitae enim malesuada, bibendum ante nec, varius tellus. Praesent vitae nisi id quam auctor lacinia at non quam. Nam nec ligula sit amet felis auctor sagittis. Nunc in risus eu urna varius laoreet quis sit amet felis. Morbi varius tempor orci, eu vestibulum nunc vestibulum ac. Nunc vehicula velit eleifend consequat porta. Suspendisse maximus dapibus orci, in vulputate massa pretium ac. Quisque malesuada aliquet aliquet."; + + const string SavedComparisonString = "Lorem\r\nipsum dolor\r\nsit amet,\r\nconsectetur\r\nadipiscing\r\nelit. Nulla\r\npulvinar\r\ninterdum\r\nimperdiet.\r\nPraesent ut\r\nauctor urna.\r\nPhasellus\r\nsollicitudin\r\nquam vitae\r\nest\r\nconvallis,\r\neu mattis\r\nlorem\r\nefficitur.\r\nMauris nulla\r\nlibero,\r\ntincidunt id\r\nipsum non,\r\nlobortis\r\ntristique\r\nmauris.\r\nDonec ut\r\nenim sed\r\nenim\r\nfermentum\r\nmolestie vel\r\nquis odio.\r\nMorbi a\r\nfermentum\r\nmassa, sit\r\namet\r\nultrices est.\r\nAenean\r\nante mi,\r\nfermentum\r\nnec\r\nrhoncus et,\r\nvulputate\r\nvel sapien.\r\nDonec\r\ntempus, leo\r\nquis luctus\r\nrhoncus,\r\naugue odio\r\npharetra\r\nlibero, ac\r\nblandit urna\r\nturpis sed\r\ndiam.\r\nVivamus\r\naugue\r\npurus,\r\neleifend et\r\njusto\r\nfacilisis,\r\nimperdiet\r\nrhoncus\r\nsem.\r\nQuisque\r\naccumsan\r\npellentesqu\r\ne elit, eget\r\nfinibus\r\nmassa\r\naccumsan\r\nin. Fusce eu\r\naccumsan\r\nenim. Cras\r\npulvinar\r\nenim vel\r\ntellus\r\nlacinia,\r\nconsectetur\r\neuismod\r\ntortor\r\nconsectetur\r\n. Praesent\r\ntincidunt\r\npretium\r\neros, ac\r\nauctor\r\nmagna\r\nluctus sed.\r\nUt porta\r\nlectus\r\nquam, non\r\nornare\r\nmauris\r\nlacinia sit\r\namet.\r\nNullam\r\negestas\r\ndolor quis\r\nmagna\r\nporttitor, ac\r\niaculis nisi\r\nhendrerit.\r\nProin at\r\nmollis\r\nlacus, in\r\nporttitor\r\nnunc.\r\nAliquam\r\nerat\r\nvolutpat.\r\nSed vel\r\negestas\r\nrisus, at\r\naliquam\r\narcu.\r\nVestibulum\r\nquis\r\nlobortis\r\nnulla. Etiam\r\npellentesqu\r\ne auctor\r\nnulla, eget\r\ntincidunt\r\nfelis\r\nrhoncus id.\r\nSed metus\r\nante,\r\nefficitur id\r\ndui eu,\r\nfermentum\r\nmollis odio.\r\nPhasellus\r\nullamcorper\r\niaculis\r\naugue vel\r\nconsequat.\r\nEtiam\r\nfringilla\r\neuismod\r\ninterdum.\r\nUt molestie\r\nmassa id\r\nfringilla\r\nlobortis.\r\nVestibulum\r\nmalesuada,\r\nante vel\r\nmattis\r\nultrices,\r\nsem ante\r\nmolestie\r\naugue, non\r\ntristique dui\r\nmi non\r\nnibh.\r\nMaecenas\r\ndictum,\r\nsem eget\r\nconvallis\r\nrhoncus,\r\nlacus enim\r\nporta\r\nneque, in\r\nposuere dui\r\nex a sapien.\r\nNam lacus\r\nnibh,\r\nposuere sed\r\nelit eget,\r\ncondimentu\r\nm facilisis\r\nligula. Cras\r\nconsectetur\r\nlacus\r\nullamcorper\r\nvelit aliquet\r\nbibendum\r\neget vel\r\nnulla.\r\nAenean\r\nvarius ac\r\nerat quis\r\nullamcorper\r\n. Donec\r\nlaoreet arcu\r\na lorem\r\nvolutpat\r\nfaucibus.\r\nVivamus\r\nvehicula leo\r\nut erat\r\nluctus\r\nscelerisque.\r\nMorbi\r\nposuere ex\r\net magna\r\negestas\r\nfacilisis.\r\nFusce\r\nscelerisque\r\nvolutpat\r\nerat\r\nbibendum\r\nhendrerit.\r\nNam blandit\r\nmi ut metus\r\npulvinar, vel\r\ntempus\r\nlacus\r\neuismod.\r\nQuisque\r\nimperdiet\r\nsit amet\r\nsapien sed\r\nultricies.\r\nPhasellus\r\nsodales,\r\nipsum vitae\r\ntincidunt\r\nfacilisis,\r\nnulla ligula\r\nfaucibus\r\nfelis, eget\r\nvehicula\r\nante lacus\r\neu lorem.\r\nInteger\r\ncongue\r\ndiam ac\r\nviverra\r\ntristique.\r\nCurabitur\r\ntristique\r\ndolor quis\r\nquam\r\npretium, et\r\nscelerisque\r\nquam\r\ndictum.\r\nMaecenas\r\nvitae\r\nsodales\r\nligula.\r\nPellentesqu\r\ne maximus\r\ndiam vel\r\nporta\r\nconvallis. Ut\r\naliquam\r\neros quis\r\nporta\r\npellentesqu\r\ne. Fusce in\r\nex ut mi\r\negestas\r\ncursus.\r\nAliquam\r\nerat\r\nvolutpat.\r\nCras laoreet\r\ncondimentu\r\nm laoreet.\r\nSed eget\r\nfacilisis\r\ntellus.\r\nMorbi\r\nviverra odio\r\nsed odio\r\nplacerat\r\nmollis. Duis\r\nturpis\r\nmetus,\r\ndignissim\r\nvarius urna\r\nquis, viverra\r\ndignissim\r\ndui.\r\nVivamus\r\nviverra at\r\nnisi quis\r\nconvallis.\r\nSuspendiss\r\ne fringilla\r\nrisus et ante\r\nsollicitudin,\r\nsed eleifend\r\nsem\r\nplacerat.\r\nProin\r\npretium\r\nblandit\r\narcu, eget\r\nrhoncus\r\nrisus\r\nhendrerit at.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nPhasellus\r\nvulputate\r\nefficitur\r\nmaximus.\r\nCras blandit\r\nnulla eu nisi\r\nauctor\r\ntempus.\r\nSed pretium\r\nlacus ac\r\nmagna\r\nvestibulum,\r\naliquam\r\nfaucibus\r\norci luctus.\r\nMauris enim\r\nlorem,\r\nvarius ut\r\nante quis,\r\nvarius\r\nviverra\r\nlectus.\r\nFusce\r\nblandit nibh\r\nvel feugiat\r\nefficitur.\r\nDonec\r\nmaximus id\r\njusto ac\r\nmollis.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nplacerat\r\nlectus et\r\npurus\r\ndictum, id\r\ncongue nisi\r\neuismod.\r\nMaecenas\r\neuismod\r\nfermentum\r\ndiam, sit\r\namet\r\ngravida\r\nmagna\r\nsuscipit a.\r\nQuisque\r\nconsectetur\r\narcu eu\r\nnunc\r\nsodales\r\nscelerisque.\r\nNulla non\r\ntincidunt\r\nnulla.\r\nPellentesqu\r\ne ut tortor\r\nvel enim\r\nconvallis\r\nmalesuada.\r\nAliquam\r\nultricies\r\nbibendum\r\nultrices.\r\nMauris\r\nrutrum ac\r\nnisl vel\r\nluctus.\r\nDonec quis\r\nnibh vitae\r\norci ultricies\r\ngravida.\r\nAliquam\r\nvitae velit\r\nporttitor\r\nlorem\r\nbibendum\r\nfringilla\r\nvolutpat a\r\neros.\r\nCurabitur at\r\ncommodo\r\ntortor. Etiam\r\nultricies,\r\nneque et\r\niaculis\r\neuismod,\r\ndiam ligula\r\nluctus mi,\r\nvitae\r\nlobortis felis\r\nlorem eu\r\nnulla. Sed a\r\nsemper ex.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNulla\r\nmauris elit,\r\npulvinar ac\r\ntortor et,\r\nluctus\r\nhendrerit\r\nnisl. In\r\negestas\r\nauctor urna\r\nvitae\r\nlaoreet.\r\nPraesent\r\nbibendum\r\negestas\r\nconvallis.\r\nProin non\r\nsuscipit\r\ntellus.\r\nNullam at\r\nnibh in urna\r\nlaoreet\r\nsodales non\r\nvel tellus.\r\nDonec in\r\nenim dui.\r\nPhasellus\r\nquis quam\r\ntincidunt,\r\npellentesqu\r\ne lorem ac,\r\nscelerisque\r\nneque.\r\nInteger nec\r\ntempus\r\nurna. Donec\r\nelit massa,\r\neleifend eu\r\nsapien sit\r\namet,\r\nmollis\r\npellentesqu\r\ne est.\r\nNullam\r\ntristique\r\ntellus\r\niaculis arcu\r\nconsectetur\r\npretium.\r\nSed\r\nvenenatis\r\nconvallis\r\nscelerisque.\r\nSuspendiss\r\ne varius\r\nurna sit\r\namet purus\r\naccumsan,\r\nid ultricies\r\nerat\r\nefficitur.\r\nCras non\r\nipsum eget\r\nnulla\r\nefficitur\r\ncommodo\r\nsit amet non\r\nlacus. Proin\r\nviverra enim\r\nsit amet\r\nenim\r\ntempus\r\nullamcorper\r\n. Class\r\naptent taciti\r\nsociosqu ad\r\nlitora\r\ntorquent per\r\nconubia\r\nnostra, per\r\ninceptos\r\nhimenaeos.\r\nDuis ac\r\nmassa\r\ninterdum,\r\ngravida ex\r\negestas,\r\nfinibus\r\npurus. Nunc\r\nconsectetur\r\ncommodo\r\nlacus, ac\r\nconvallis\r\nquam\r\nlobortis eu.\r\nSed\r\nconvallis\r\ntempor\r\ncommodo.\r\nNulla sed\r\nconvallis\r\nmauris.\r\nDonec\r\nvenenatis\r\nnisi est, ac\r\nullamcorper\r\nmi pretium\r\nquis. Donec\r\nvitae eros at\r\nipsum\r\ninterdum\r\nscelerisque\r\nnec vitae\r\nnisi. Sed\r\nvestibulum\r\nerat ac\r\nbibendum\r\ndapibus.\r\nMorbi nec\r\nelit id quam\r\ntristique\r\ncursus id\r\nsed sem.\r\nPraesent\r\nnon ante\r\nenim.\r\nPellentesqu\r\ne habitant\r\nmorbi\r\ntristique\r\nsenectus et\r\nnetus et\r\nmalesuada\r\nfames ac\r\nturpis\r\negestas.\r\nPraesent\r\nnon mauris\r\ndui.\r\nAliquam\r\nrhoncus\r\nmattis ante\r\nsed\r\nvenenatis.\r\nVivamus\r\nvehicula\r\nsed sapien\r\nsed dictum.\r\nIn aliquet,\r\nurna\r\nefficitur\r\ntincidunt\r\nlobortis,\r\nnibh justo\r\ntristique\r\npurus, sed\r\nvolutpat\r\nrisus magna\r\net\r\nlibero.Susp\r\nendisse\r\nlectus justo,\r\nvarius eget\r\narcu et,\r\nsemper\r\nlaoreet erat.\r\nQuisque\r\neget lacus\r\nornare,\r\npellentesqu\r\ne erat sit\r\namet,\r\nvulputate\r\nfelis. Duis\r\nluctus,\r\nmassa a\r\npellentesqu\r\ne mollis,\r\nmassa elit\r\nconvallis\r\nmi, vel\r\nbibendum\r\nex ex eu\r\npurus.\r\nSuspendiss\r\ne vel\r\nfermentum\r\nurna, ac\r\ncommodo\r\nenim.\r\nMauris\r\ntincidunt\r\ncursus elit,\r\na volutpat\r\nlibero\r\ncommodo\r\net. Etiam\r\ndapibus\r\nlibero\r\nvenenatis\r\ntellus\r\nlobortis, vel\r\nlacinia elit\r\nfaucibus.\r\nMaecenas\r\nsemper sed\r\nquam quis\r\nfinibus.\r\nInteger\r\nefficitur,\r\nlibero\r\nimperdiet\r\nsollicitudin\r\ncommodo,\r\nelit arcu\r\nvulputate\r\nest, eget\r\nfinibus mi\r\nurna sit\r\namet\r\nmagna.\r\nCras\r\nullamcorper\r\nconsequat\r\nornare.\r\nFusce\r\nconvallis\r\nnunc vel\r\nrisus\r\ncursus, at\r\nmaximus\r\nligula\r\ncursus.\r\nPellentesqu\r\ne vulputate\r\nrisus libero,\r\neget cursus\r\nnibh\r\nsodales\r\nsed. Donec\r\naccumsan\r\nsem et\r\nmassa\r\nsemper, id\r\ndignissim\r\nvelit\r\nvehicula.Cr\r\nas cursus\r\nipsum ac\r\nerat\r\nvehicula,\r\nnec iaculis\r\npurus\r\ndictum.\r\nQuisque\r\nlacinia elit\r\nvitae leo\r\ndictum, vel\r\ndignissim\r\nvelit\r\ndapibus.\r\nAenean sem\r\nnisi,\r\nfaucibus\r\ninterdum\r\njusto eu,\r\neuismod\r\nporttitor ex.\r\nMorbi et\r\nlectus\r\nlectus. Duis\r\nneque felis,\r\nsuscipit at\r\nscelerisque\r\neu,\r\nscelerisque\r\nid orci.\r\nCurabitur et\r\nplacerat\r\nipsum.\r\nProin\r\ngravida\r\nsapien nisl,\r\net varius\r\nipsum\r\nmollis nec.\r\nQuisque\r\ndignissim\r\nconsectetur\r\nfeugiat.\r\nAenean\r\neros purus,\r\nlaoreet\r\ninterdum\r\nrutrum at,\r\naliquet sit\r\namet\r\nlectus.\r\nDonec\r\ngravida\r\nlorem ut\r\ntincidunt\r\nlaoreet.\r\nDonec\r\nconsequat\r\nviverra\r\nligula, in\r\naccumsan\r\nmi\r\nbibendum\r\nscelerisque.\r\nQuisque ac\r\nrisus justo.\r\nMorbi\r\nmagna\r\narcu,\r\negestas nec\r\nluctus\r\ncommodo,\r\ncursus eget\r\nnunc.\r\nVivamus\r\neuismod\r\nlorem ex, et\r\nmaximus\r\nfelis\r\nhendrerit\r\neget.\r\nNullam\r\nullamcorper\r\neuismod\r\nligula, et\r\niaculis\r\nligula\r\nultricies a.\r\nFusce\r\naliquam,\r\nenim vel\r\nfermentum\r\nultrices, elit\r\nquam\r\nsemper\r\nerat, vitae\r\nsemper velit\r\naugue non\r\nmagna.Quis\r\nque\r\nmaximus\r\nsemper\r\narcu, id\r\npellentesqu\r\ne est\r\ntempus a.\r\nPhasellus\r\nlacus elit,\r\nauctor sit\r\namet lacinia\r\na, dapibus\r\nvitae velit.\r\nPhasellus ut\r\npharetra\r\njusto, ut\r\nultricies\r\nerat. Sed\r\nmolestie\r\nsapien vel\r\ninterdum\r\nlobortis.\r\nNulla\r\nfacilisi.\r\nVestibulum\r\nante ipsum\r\nprimis in\r\nfaucibus\r\norci luctus\r\net ultrices\r\nposuere\r\ncubilia\r\ncurae; Nulla\r\nnec mauris\r\nquis nisi\r\nvulputate\r\ngravida quis\r\nnec\r\nvelit.Nam et\r\ncongue\r\nipsum.\r\nNulla vel elit\r\nnon dolor\r\nmollis\r\naliquet vel\r\nat magna.\r\nPellentesqu\r\ne nec\r\nfacilisis elit.\r\nIn vulputate\r\nquis sem\r\nporta\r\nsuscipit.\r\nNullam sed\r\nex ornare\r\nnibh\r\nsuscipit\r\nmattis quis\r\nnon lacus.\r\nMauris vel\r\nex urna.\r\nVivamus\r\nultricies\r\nsapien sit\r\namet sapien\r\nvehicula\r\ngravida.\r\nDonec\r\nfeugiat\r\nvolutpat\r\nquam.\r\nVestibulum\r\nauctor\r\ndictum nisl,\r\nid hendrerit\r\nmetus\r\nullamcorper\r\nsed. Nulla\r\nmaximus\r\nlacus vel\r\nmollis\r\nmaximus.\r\nNulla\r\nlaoreet\r\nplacerat\r\nquam eu\r\nviverra.\r\nEtiam\r\nfeugiat\r\naccumsan\r\nnisl a\r\ncondimentu\r\nm. Sed\r\nultricies\r\nante ante,\r\nac auctor\r\nligula\r\ngravida nec.\r\nPraesent a\r\nneque\r\ndignissim,\r\nsagittis felis\r\nsit amet,\r\ncondimentu\r\nm turpis.\r\nFusce at leo\r\nvel est\r\nblandit\r\nmalesuada.\r\nPellentesqu\r\ne et neque\r\nnon metus\r\npellentesqu\r\ne imperdiet.\r\nPraesent\r\npellentesqu\r\ne lacinia\r\nlorem, et\r\ntristique\r\ntellus\r\nefficitur id.\r\nSuspendiss\r\ne aliquet\r\nultricies\r\njusto vitae\r\ninterdum.\r\nCras\r\ntristique\r\nviverra\r\nquam, eget\r\ngravida mi\r\nfermentum\r\nimperdiet.\r\nSed\r\nimperdiet\r\nvitae purus\r\nut volutpat.\r\nNulla\r\nlacinia elit\r\nin\r\nfermentum\r\nconsectetur\r\n. Phasellus\r\ncommodo\r\nut nisl sit\r\namet\r\nsagittis.\r\nDuis ac\r\nornare orci.\r\nVivamus vel\r\nenim\r\nposuere,\r\npharetra ex\r\nvel,\r\nelementum\r\nest.\r\nVestibulum\r\ncommodo\r\nluctus\r\nmetus eget\r\nmaximus.\r\nSuspendiss\r\ne a nulla a\r\nodio\r\neleifend\r\nfaucibus.\r\nSuspendiss\r\ne semper\r\nlacus non\r\nporttitor\r\naliquet.\r\nCras ac\r\nscelerisque\r\nmagna, et\r\npulvinar\r\njusto.\r\nInteger\r\ncursus\r\npulvinar\r\nfringilla.\r\nMauris\r\nimperdiet\r\nnibh sit\r\namet\r\ntempor\r\nlaoreet.\r\nMorbi\r\ntincidunt\r\ntortor ex, sit\r\namet\r\nmaximus\r\npurus\r\ntristique\r\nquis.\r\nQuisque\r\nsed\r\nhendrerit\r\nvelit. Mauris\r\nmattis nibh\r\nut eros\r\nluctus, eget\r\nmattis\r\nmassa\r\nauctor.\r\nPhasellus\r\neu neque at\r\naugue\r\ngravida\r\nsagittis nec\r\nnon tortor.\r\nEtiam\r\nporttitor\r\nsem\r\nsodales mi\r\nullamcorper\r\ngravida. In\r\nin dictum\r\norci. In vitae\r\nvestibulum\r\nquam. Cras\r\naugue eros,\r\ntincidunt ac\r\nelit posuere,\r\nsollicitudin\r\nefficitur\r\nlectus.\r\nPraesent\r\nquis\r\nsodales\r\nnisl. Proin\r\nsit amet\r\nmolestie\r\nest. In\r\ncommodo\r\nmauris vel\r\nmauris\r\nefficitur,\r\nnec mollis\r\nmauris\r\nsagittis.\r\nCras ligula\r\nnibh,\r\negestas sit\r\namet eros\r\nin, lacinia\r\ntristique\r\nmagna.\r\nCras risus\r\nlibero,\r\nlacinia eget\r\nlibero vitae,\r\nmaximus\r\naliquet\r\nnibh. Mauris\r\nid sodales\r\npurus, vitae\r\ndictum\r\nlectus. Cras\r\nconsectetur\r\nligula velit,\r\ntempus\r\npulvinar\r\nlacus\r\nporttitor\r\nvitae.\r\nPhasellus\r\neget tellus\r\nipsum.\r\nDonec\r\ninterdum\r\nlaoreet elit\r\nnon\r\nvestibulum.\r\nCras sed\r\nurna\r\nullamcorper\r\n, aliquam\r\nerat eget,\r\nporta orci.\r\nVestibulum\r\neget congue\r\nnulla. Sed\r\nsem tortor,\r\neuismod at\r\nrutrum id,\r\nsagittis a\r\nnunc. Duis\r\nin nibh\r\nfacilisis,\r\ndignissim\r\npurus ut,\r\nhendrerit\r\nmagna. Sed\r\nsemper\r\nligula id\r\nmassa\r\nelementum,\r\nnon\r\nmalesuada\r\nvelit\r\negestas.\r\nNullam\r\ndictum, mi\r\nnec\r\neuismod\r\nsagittis,\r\nligula leo\r\nullamcorper\r\ndolor, quis\r\nfaucibus\r\nodio metus\r\neget magna.\r\nUt gravida\r\nmetus non\r\nmetus\r\nbibendum\r\nbibendum.\r\nIn sagittis\r\neleifend\r\naliquet.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nNam mollis\r\nsagittis\r\nfelis, in\r\nfaucibus\r\ntortor\r\npretium vel.\r\nNam nec\r\nenim\r\nmetus.\r\nDonec in\r\naugue arcu.\r\nProin non\r\nlobortis\r\npurus, sit\r\namet lacinia\r\nelit.\r\nSuspendiss\r\ne quis eros\r\ncondimentu\r\nm, blandit\r\njusto sit\r\namet,\r\nlobortis nisl.\r\nSuspendiss\r\ne maximus\r\nmassa sed\r\nurna tempor\r\nornare.\r\nNunc\r\nmalesuada\r\npurus odio,\r\neu luctus\r\nlectus\r\nauctor nec.\r\nMorbi\r\nauctor\r\npellentesqu\r\ne auctor.\r\nSed\r\nullamcorper\r\n, ex vitae\r\naliquam\r\nvulputate,\r\nest diam\r\nfeugiat mi,\r\nid porttitor\r\nlectus orci\r\nac leo.\r\nDonec sit\r\namet velit\r\npulvinar,\r\nvenenatis\r\nturpis ut,\r\ninterdum\r\nligula.\r\nInterdum et\r\nmalesuada\r\nfames ac\r\nante ipsum\r\nprimis in\r\nfaucibus.\r\nVestibulum\r\neu lacus\r\nurna.\r\nMaecenas\r\nsem nulla,\r\naccumsan\r\neu ultricies\r\nsed, tempor\r\nvel magna.\r\nCras aliquet\r\nsollicitudin\r\nsapien ac\r\npulvinar.\r\nPraesent ac\r\nsodales mi.\r\nInteger vitae\r\nmauris\r\nmassa.\r\nMaecenas\r\niaculis orci\r\net faucibus\r\ninterdum.\r\nNunc nec\r\nmaximus\r\nfelis, sed\r\nfinibus\r\nquam.\r\nPellentesqu\r\ne felis\r\nmassa,\r\nvestibulum\r\nin tellus\r\nvitae,\r\ncongue\r\ntincidunt\r\njusto. Nunc\r\nvitae enim\r\nmalesuada,\r\nbibendum\r\nante nec,\r\nvarius\r\ntellus.\r\nPraesent\r\nvitae nisi id\r\nquam\r\nauctor\r\nlacinia at\r\nnon quam.\r\nNam nec\r\nligula sit\r\namet felis\r\nauctor\r\nsagittis.\r\nNunc in\r\nrisus eu\r\nurna varius\r\nlaoreet quis\r\nsit amet\r\nfelis. Morbi\r\nvarius\r\ntempor orci,\r\neu\r\nvestibulum\r\nnunc\r\nvestibulum\r\nac. Nunc\r\nvehicula\r\nvelit\r\neleifend\r\nconsequat\r\nporta.\r\nSuspendiss\r\ne maximus\r\ndapibus\r\norci, in\r\nvulputate\r\nmassa\r\npretium ac.\r\nQuisque\r\nmalesuada\r\naliquet\r\naliquet."; + var savedStrings = SavedComparisonString.Split("\r\n"); + + ITextShaper shaper = new TextShaper(SystemFontsEngine, font); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapText( + Lorem20Str, + 11f, + 54, + ShapingOptions.Full + ); + + List faultyStrings = new(); + List excpectedStrings = new(); + List indiciesOfDifferingString = new(); + + for (int i = 0; i < wrappedLines.Count(); i++) + { + if (savedStrings[i] != wrappedLines[i]) + { + indiciesOfDifferingString.Add(i); + faultyStrings.Add(wrappedLines[i]); + excpectedStrings.Add(savedStrings[i]); + } + } + + if (indiciesOfDifferingString.Count != 0) + { + //The start of indicies diverging + Assert.IsNull(indiciesOfDifferingString[0]); + Assert.AreEqual(faultyStrings[0], excpectedStrings[0]); + } + + Assert.AreEqual(0, faultyStrings.Count); + } + + [TestMethod] + public void WrapText_WithPreExistingWidth_AccountsForIt() + { + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Regular); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Measure "Hello " to get its width + var testShaper = SystemFontsEngine.GetTextShaper("Calibri"); + var shaped = testShaper.Shape("Hello ", ShapingOptions.Default); + double preWidth = shaped.GetWidthInPoints(11f); + + // Act - Add text with pre-existing width, narrow max width + var lines = layout.WrapText("world test", 11f, preWidth + 50, preWidth); + + // Assert - Should wrap because first line already has content + Assert.IsTrue(lines.Count >= 1); + } + + [TestMethod] + public void WrapText_EmptyString_ReturnsEmptyLine() + { + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Regular); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Act + var lines = layout.WrapText("", 11f, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual(string.Empty, lines[0]); + } + + [TestMethod] + public void WrapText_WithKerning_MeasuresCorrectly() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = TestFolderEngine.GetTextShaper("Roboto"); + var layout = new TextLayoutEngine(TestFolderEngine, shaper); + + // Act - "AV" has kerning in Roboto + var withKerning = layout.WrapText("AV", 11f, 1000, ShapingOptions.Default); + var withoutKerning = layout.WrapText("AV", 11f, 1000, ShapingOptions.None); + + // Assert - Both should be single line, but measured differently + Assert.AreEqual(1, withKerning.Count); + Assert.AreEqual(1, withoutKerning.Count); + Assert.AreEqual("AV", withKerning[0]); + Assert.AreEqual("AV", withoutKerning[0]); + } + + #endregion + + #region Rich Text Wrapping Tests + + [TestMethod] + public void ImportingFromCells() + { + + } + + [TestMethod] + public void MyVeryGoodRichTextWrapper() + { + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + + //Text containing emoji + var inputText = "My long and 😝😱 bothersome 😝😱 text"; + var shapedText = (ShapedText)shaper.Shape(inputText); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var text = layout.WrapText(inputText, 12, 20); + + + //// Act + //var lines = layout.WrapRichText(fragments, 1000); + + //var layout = new TextLayoutEngine(shaper); + } + + [TestMethod] + public void WrapRichText_SingleFragment_BehavesLikeSingleFont() + { + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Regular); + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "Hello world", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + } + }; + + // Act + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("Hello world", lines[0]); + } + + [TestMethod] + public void WrapRichText_MultipleFragments_ConcatenatesCorrectly() + { + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Arial", FontSubFamily.Regular); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = SystemFontsEngine.GetTextShaper("Calibri"); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "Hello ", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "world", + Font = new FontFormatBase { Family = "Arial", Size = 12, SubFamily = FontSubFamily.Bold } + } + }; + + // Act + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("Hello world", lines[0]); + } + + [TestMethod] + public void WrapRichText_DifferentFonts_WrapsCorrectly() + { + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Regular); + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "This is ", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "mixed ", + Font = new FontFormatBase { Family = "Arial", Size = 14, SubFamily = FontSubFamily.Bold } + }, + new TextFragment + { + Text = "fonts", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + } + }; + + // Act - narrow width to force wrapping + var lines = layout.WrapRichText(fragments, 80); + + // Assert + Assert.IsTrue(lines.Count >= 1); + + // Check that we got the expected lines + Assert.AreEqual("This is mixed", lines[0]); + Assert.AreEqual("fonts", lines[1]); + + // When joining wrapped lines with spaces, we get back close to original + string rejoined = string.Join(" ", lines); + Assert.AreEqual("This is mixed fonts", rejoined); + } + + + private FontSubFamily GetFontSubType(MeasurementFontStyles Style) + { + if ((Style & (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) == (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) + { + return FontSubFamily.BoldItalic; + } + else if ((Style & MeasurementFontStyles.Bold) == MeasurementFontStyles.Bold) + { + return FontSubFamily.Bold; + } + else if ((Style & MeasurementFontStyles.Italic) == MeasurementFontStyles.Italic) + { + return FontSubFamily.Italic; + } + + return FontSubFamily.Regular; + } + + [TestMethod] + public void WrapLongRichTextWord() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + var mFont = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Regular + }; + + var longWord = "pellentesquer"; + + var fragment = new TextFragment() { Text = longWord, Font = mFont }; + var fragLst = new List() { fragment }; + + ITextShaper shaper = SystemFontsEngine.GetShaperForFont(mFont); + using var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var wrappedLines = layout.WrapRichText(fragLst, 54); + + Assert.AreEqual("pellentesqu", wrappedLines[0]); + Assert.AreEqual("er", wrappedLines[1]); + } + + [TestMethod] + public void WrapRichTextDifficultCase() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + var sw = System.Diagnostics.Stopwatch.StartNew(); + var lap = sw.ElapsedMilliseconds; + + List lstOfRichText = new() { "TextBox\r\na\r\n", "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + var font1 = new MeasurementFont() { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Regular }; + var font2 = new MeasurementFont() { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Bold }; + var font3 = new MeasurementFont() { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Underline }; + var font4 = new MeasurementFont() { FontFamily = "Aptos Narrow", Size = 11, Style = MeasurementFontStyles.Strikeout }; + var font5 = new MeasurementFont() { FontFamily = "Goudy Stout", Size = 16, Style = MeasurementFontStyles.Regular }; + var font6 = new MeasurementFont() { FontFamily = "Aptos Narrow", Size = 24, Style = MeasurementFontStyles.Regular }; + List fonts = new() { font1, font2, font3, font4, font5, font6 }; + + var fragments = new List(); + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currFrag = new TextFragment() { Text = lstOfRichText[i] }; + currFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currFrag); + } + + lap = sw.ElapsedMilliseconds; + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + + lap = sw.ElapsedMilliseconds; + + var startFont = SystemFontsEngine.LoadFont(font1.FontFamily, GetFontSubType(font1.Style)); + + var goudyTest = SystemFontsEngine.LoadFont("Goudy Stout", FontSubFamily.Regular); + System.Console.WriteLine("[DIAG] Goudy family=" + goudyTest.FullName + + " RawData.Length=" + (goudyTest.RawData?.Length ?? -1)); + + var aptosTest = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + System.Console.WriteLine("[DIAG] Aptos family=" + aptosTest.FullName + + " RawData.Length=" + (aptosTest.RawData?.Length ?? -1)); + + System.Console.WriteLine("[DIAG] maxSizePoints=" + maxSizePoints); + + lap = sw.ElapsedMilliseconds; + + var shaper = new TextShaper(SystemFontsEngine, startFont); + + lap = sw.ElapsedMilliseconds; + + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + lap = sw.ElapsedMilliseconds; + + var wrappedLines = layout.WrapRichText(fragments, maxSizePoints); + + lap = sw.ElapsedMilliseconds; + + + Assert.AreEqual("TextBox", wrappedLines[0]); + Assert.AreEqual("a", wrappedLines[1]); + Assert.AreEqual("TextBox2ra underlineLa", wrappedLines[2]); + Assert.AreEqual("StrikeGoudy size", wrappedLines[3]); + Assert.AreEqual("16SvgSize 24", wrappedLines[4]); + } + + [TestMethod] + public void MeasureBigGoudy() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + List lstOfRichText = new() { "TextBox2ra underlineLa Strike", "Goudysize16SvgSize24" }; + + var regFont = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + + var goudyFont = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + List fonts = new() { regFont, goudyFont }; + + var shaper = (TextShaper)SystemFontsEngine.GetShaperForFont(regFont); + var layout = SystemFontsEngine.GetTextLayoutEngineForFont(regFont); + + var maxSizeInPoints = 225d; + + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currFrag = new TextFragment() { Text = lstOfRichText[i] }; + currFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currFrag); + } + + //var test = "TextBox2ra underlineLa StrikeGoudysize16SvgSize24"; + ////var secondTest = "TextBox2ra underlineLa StrikeGoudy".ToArray(); + + var wrappedLines = layout.WrapRichTextLines(fragments, maxSizeInPoints); + + var txtWidthsingle = shaper.MeasureTextInPixels("E", 16, 96, ShapingOptions.Full); + var txtWidth = shaper.MeasureTextInPixels("EEEEEEEEEE", 16, 96, ShapingOptions.Full); + var txtWidthAlt = shaper.MeasureTextInPixels("EEEEEEEEEE", 16, 96, ShapingOptions.Fast); + + var txtWidthLowSize = shaper.MeasureTextInPixels("E", 11, 96, ShapingOptions.Fast); + var txtWidthHighSize= shaper.MeasureTextInPixels("E", 72, 96, ShapingOptions.Fast); + var txtWidthHighSize10 = shaper.MeasureTextInPixels("EEEEEEEEEE", 72, 96, ShapingOptions.Fast); + + var pts16 = shaper.MeasureTextInPoints("E", 16); + var pts = shaper.MeasureTextInPoints("E", 72); + var pts2 = shaper.MeasureTextInPoints("E", 96); + + var txtWidthMaxSizeSingle = shaper.MeasureTextInPixels("E", 96, 72, ShapingOptions.Full); + var txtWidthMaxSizeSingleFast = shaper.MeasureTextInPixels("E", 96, 72, ShapingOptions.Fast); + + var txtWidthMaxSizeSingle96 = shaper.MeasureTextInPixels("E", 96, 96, ShapingOptions.Full); + var txtWidthMaxSizeSingleFast96 = shaper.MeasureTextInPixels("E", 96, 96, ShapingOptions.Fast); + + //Assert.AreEqual(16, txtWidthLowSize); + //Assert.AreEqual(97, txtWidthHighSize); + + //Assert.AreEqual(97, txtWidthHighSize); + //Assert.AreEqual(23, txtWidthsingle); + //Assert.AreEqual(249,txtWidth); + + //var wrappedLines = layout.WrapRichTextLines(fragments, maxSizeInPoints); + + ////E in goudy stout 16 should be equal to 22 px or 16.5 points + //Assert.AreEqual(16.5d, wrappedLines[0].LineFragments[0].Width); + //Assert.AreEqual(16.5d, wrappedLines[0].LineFragments[1].Width); + } + + [TestMethod] + public void EnsureRichTextLineWrappingSameAsNonRichWhenNoWrap() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + List comparatorLst = new() { "Strike", "Goudy size"}; + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var points1 = shaper.MeasureTextInPoints(comparatorLst[0], 11); + + var font2 = SystemFontsEngine.LoadFont("Goudy Stout", FontSubFamily.Regular); + var otherShaper = new TextShaper(SystemFontsEngine, font2); + + var points2 = otherShaper.MeasureTextInPoints(comparatorLst[1], 16); + + var pointsTotal = points1 + points2; + Assert.AreEqual(202.8916f, pointsTotal); + + var comparatorFragments = new List(); + + var font11 = new RichTextFormatSimple() + { + Family = "Aptos Narrow", + Size = 11, + StrikeType = 1 + }; + + + + var font22 = new RichTextFormatSimple() + { + Family = "Goudy Stout", + Size = 16, + }; + + var frag1 = new TextFragment() { Font = font11, Text = comparatorLst[0] }; + var frag2 = new TextFragment() { Font = font22, Text = comparatorLst[1] }; + comparatorFragments.Add(frag1); + comparatorFragments.Add(frag2); + + var startFont = SystemFontsEngine.LoadFont(font11.Family, font11.SubFamily); + var goudyFont = SystemFontsEngine.LoadFont(font22.Family, font22.SubFamily); + + ITextShaper shaper2 = new TextShaper(SystemFontsEngine, font); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapRichTextLines(comparatorFragments, 225d); + + Assert.AreEqual(pointsTotal, wrappedLines[0].Width); + Assert.AreEqual(points1, wrappedLines[0].InternalLineFragments[0].Width); + Assert.AreEqual(points2, wrappedLines[0].InternalLineFragments[1].Width); + } + + [TestMethod] + public void EnsureRichTextLineWrappingSameAsNonRichWhenNoWrapAndSpaceTrail() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + RequireFont(SystemFontsEngine, "Goudy Stout"); + + List comparatorLst = new() { "Strike", "Goudy size " }; + + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var points1 = shaper.MeasureTextInPoints(comparatorLst[0], 11); + + var font2 = SystemFontsEngine.LoadFont("Goudy Stout", FontSubFamily.Regular); + var otherShaper = new TextShaper(SystemFontsEngine, font2); + + var points2 = otherShaper.MeasureTextInPoints(comparatorLst[1], 16); + + var pointsTotal = points1 + points2; + Assert.AreEqual(210.8916f, pointsTotal); + + var comparatorFragments = new List(); + + var font11 = new RichTextFormatSimple() + { + Family = "Aptos Narrow", + Size = 11, + StrikeType = 1 + }; + + var font22 = new RichTextFormatSimple() + { + Family = "Goudy Stout", + Size = 16, + }; + + var frag1 = new TextFragment() { Font = font11, Text = comparatorLst[0] }; + var frag2 = new TextFragment() { Font = font22, Text = comparatorLst[1] }; + comparatorFragments.Add(frag1); + comparatorFragments.Add(frag2); + + var startFont = SystemFontsEngine.LoadFont(font11.Family, font11.SubFamily); + var goudyFont = SystemFontsEngine.LoadFont(font22.Family, font22.SubFamily); + + ITextShaper shaper2 = new TextShaper(SystemFontsEngine, font); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapRichTextLines(comparatorFragments, 225d); + + Assert.AreEqual(pointsTotal, wrappedLines[0].Width); + Assert.AreEqual(points1, wrappedLines[0].InternalLineFragments[0].Width); + Assert.AreEqual(points2, wrappedLines[0].InternalLineFragments[1].Width); + var noSpaceWidth = wrappedLines[0].GetWidthWithoutTrailingSpaces(); + Assert.AreEqual(202.8916f, noSpaceWidth); + } + + [TestMethod] + public void EnsureLineFragmentsAreMeasuredCorrectlyWhenWrapping() + { + RequireFont(SystemFontsEngine,"Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + List lstOfRichText = new() { "TextBox2", "ra underline", "La Strike", "Goudy size 16"}; + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + List fonts = new() { font2, font3, font4, font5}; + var fragments = new List(); + + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i]}; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + var startFont = SystemFontsEngine.LoadFont(font2.FontFamily, GetFontSubType(font2.Style)); + + var shaper = new TextShaper(SystemFontsEngine, startFont); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var wrappedLines = layout.WrapRichTextLines(fragments, maxSizePoints); + + Assert.AreEqual(12.55224609375d, wrappedLines[0].InternalLineFragments[2].Width); + Assert.AreEqual(202.8916f, wrappedLines[1].GetWidthWithoutTrailingSpaces()); + + List smallestTextFragments = new List(); + + //Ensure each linefragment can get correct text + foreach(var line in wrappedLines) + { + foreach(var lf in line.InternalLineFragments) + { + var text = line.GetLineFragmentText(lf); + smallestTextFragments.Add(text); + } + } + + Assert.AreEqual(6, smallestTextFragments.Count); + Assert.AreEqual("TextBox2", smallestTextFragments[0]); + Assert.AreEqual("ra underline", smallestTextFragments[1]); + Assert.AreEqual("La", smallestTextFragments[2]); + Assert.AreEqual("Strike", smallestTextFragments[3]); + Assert.AreEqual("Goudy size", smallestTextFragments[4]); + Assert.AreEqual("16", smallestTextFragments[5]); + } + + private void GenerateTextFragments(List lstOfRichText, List fonts, ref List fragments) + { + for (int i = 0; i < lstOfRichText.Count(); i++) + { + var currentFrag = new TextFragment() { Text = lstOfRichText[i] }; + currentFrag.RichTextOptions.SetFont(fonts[i]); + fragments.Add(currentFrag); + } + } + + [TestMethod] + public void TestParagraphs() + { + + List lstOfRichText = new() { "MyparticularilyLongWord", "WithAbsolutelyNoSpacesAtAllJustToBeDifficult" }; + var font = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + var font2 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + GenerateTextFragments(lstOfRichText, fonts, ref fragments); + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var styleRuns = paragraph.GetTextOfAllTextRuns(); + + Assert.AreEqual(lstOfRichText[0], styleRuns[0]); + Assert.AreEqual(lstOfRichText[1], styleRuns[1]); + + + var layout = SystemFontsEngine.GetTextLayoutEngineForFont(font); + var wrappedLines = layout.WrapRichTextLines(fragments, 225d); + + var wrappedLinesPara = paragraph.Wrap(225d); + + Assert.AreEqual(wrappedLines.Count, wrappedLinesPara.Count); + + for (int i = 0; i < wrappedLines.Count; i++) + { + Assert.AreEqual(wrappedLines[i].Text, wrappedLinesPara[i].Text); + Assert.AreEqual(wrappedLines[i].Width, wrappedLinesPara[i].Width); + } + } + + [TestMethod] + public void TestLayoutSystemParagraphChars() + { + List lstOfRichText = new() { "Here comes lorem ipsum\u2029 " + + "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit amet consectetur adipisci[ng] velit, sed quia non numquam [do] eius modi tempora inci[di]dunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum[d] exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? [D]Quis autem vel eum i[r]ure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?\u2029 " + + "At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem reru[d]um facilis est e[r]t expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellend[a]us. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.\u2029 " + + "Let's see if we can recognize unicode paragraph separators" }; + var font = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Bold + }; + var fragments = new List() + { + new TextFragment() {Text = lstOfRichText[0], Font = font } + }; + + var layout = new LayoutSystem(SystemFontsEngine, fragments); + Assert.AreEqual(3, layout.GetParagraphSeparatorCount()); + } + + [TestMethod] + public void TestParagraphs_DifficultCase() + { + List lstOfRichText = new() { "TextBox2", "ra underline", "La Strike", "Goudy size 16" }; + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + List fonts = new() { font2, font3, font4, font5 }; + var fragments = new List(); + + GenerateTextFragments(lstOfRichText, fonts, ref fragments); + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var wrappedLines = paragraph.Wrap(225d); + + var line1 = wrappedLines[0]; + } + + [TestMethod] + public void EnsureCorrectTotalIndex() + { + List lstOfRichText = new() { "aaaaaaaa aa aaaaaaaaaLa Strike", "Goudy size 16" }; + var font = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + var font2 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + GenerateTextFragments(lstOfRichText, fonts, ref fragments); + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + var wrappedLines = paragraph.Wrap(225d); + + Assert.AreEqual("StrikeGoudy size", wrappedLines[1].Text); + Assert.AreEqual(24, wrappedLines[1].LineFragments[0].StartFullTextIdx); + Assert.AreEqual(24, wrappedLines[1].LineFragments[0].StartRtIdx); + } + + [TestMethod] + public void EnsureRTCharIdxBecomesCorrectWhenBreaking() + { + List lstOfRichText = new() { "MyparticularilyLongWord", "WithAbsolutelyNoSpacesAtAllJustToBeDifficult" }; + var font = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + var font2 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new List() { font, font2 }; + + var fragments = new List(); + + GenerateTextFragments(lstOfRichText, fonts, ref fragments); + + var paragraph = new LayoutSystem(SystemFontsEngine, fragments); + + var layout = SystemFontsEngine.GetTextLayoutEngineForFont(font); + var wrappedLines = layout.WrapRichTextLines(fragments, 225d); + + Assert.AreEqual(5, wrappedLines[1].LineFragments[0].StartRtIdx); + Assert.AreEqual(16, wrappedLines[2].LineFragments[0].StartRtIdx); + Assert.AreEqual(28, wrappedLines[3].LineFragments[0].StartRtIdx); + Assert.AreEqual(40, wrappedLines[4].LineFragments[0].StartRtIdx); + } + + [TestMethod] + public void WrapRichTextDifficultCaseCompare() + { + List lstOfRichText = new() { "TextBox\r\na\r\n", "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + var font1 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + + var font6 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 24, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new() { font1, font2, font3, font4, font5, font6 }; + var fragments = new List(); + + GenerateTextFragments(lstOfRichText, fonts, ref fragments); + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + var startFont = SystemFontsEngine.LoadFont(font1.FontFamily, GetFontSubType(font1.Style)); + + var shaper = new TextShaper(SystemFontsEngine, startFont); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var wrappedLines = layout.WrapRichTextLines(fragments, maxSizePoints); + var measurer = SystemFontsEngine.GetTextLayoutEngineForFont(font1); + + Assert.AreEqual("TextBox", wrappedLines[0].Text); + Assert.AreEqual("a", wrappedLines[1].Text); + Assert.AreEqual("TextBox2ra underlineLa", wrappedLines[2].Text); + Assert.AreEqual("StrikeGoudy size", wrappedLines[3].Text); + Assert.AreEqual("16SvgSize 24", wrappedLines[4].Text); + + //Rather large epsilon but the char widths are each individually more correct now + var epsilon = 0.1d; + + Assert.AreEqual(32.87646484375d, wrappedLines[0].Width, epsilon); + Assert.AreEqual(5.30126953125d, wrappedLines[1].Width, epsilon); + Assert.AreEqual(104.9453125d, wrappedLines[2].Width, epsilon); + Assert.AreEqual(210.890625d, wrappedLines[3].Width, epsilon); + Assert.AreEqual(127.04296875d, wrappedLines[4].Width, epsilon); + + var line1FragmentsNew = wrappedLines[0].InternalLineFragments; + Assert.AreEqual(32.87646484375d, line1FragmentsNew[0].Width, epsilon); + + var line2FragmentsNew = wrappedLines[1].InternalLineFragments; + + Assert.AreEqual(5.30126953125d, line2FragmentsNew[0].Width, epsilon); + + var line3FragmentsNew = wrappedLines[2].InternalLineFragments; + + Assert.AreEqual(40.21875d, line3FragmentsNew[0].Width, epsilon); + Assert.AreEqual(52.16943359375d, line3FragmentsNew[1].Width, epsilon); + Assert.AreEqual(12.55712890625d, line3FragmentsNew[2].Width, epsilon); + + var line4FragmentsNew = wrappedLines[3].InternalLineFragments; + + Assert.AreEqual(24.86328125d, line4FragmentsNew[0].Width, epsilon); + Assert.AreEqual(186.02734375d, line4FragmentsNew[1].Width, epsilon); + + var line5FragmentsNew = wrappedLines[4].InternalLineFragments; + + Assert.AreEqual(26.390625d, line5FragmentsNew[0].Width, epsilon); + Assert.AreEqual(100.65234375d, line5FragmentsNew[1].Width, epsilon); + } + + [TestMethod] + public void WrapRichText_WordSpanningFragments_MeasuresCorrectly() + { + RequireFont(SystemFontsEngine, "Calibri"); + RequireFont(SystemFontsEngine, "Arial"); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // "Hello" split across two fragments with different fonts + var fragments = new List + { + new TextFragment + { + Text = "Hel", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "lo world", + Font = new FontFormatBase { Family = "Arial", Size = 11 } + } + }; + + // Act + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("Hello world", lines[0]); + } + + [TestMethod] + public void WrapRichText_WithLineBreaks_PreservesBreaks() + { + RequireFont(SystemFontsEngine, "Calibri"); + RequireFont(SystemFontsEngine, "Arial"); + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "Line 1\n", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "Line 2", + Font = new FontFormatBase { Family = "Arial", Size = 11 } + } + }; + + // Act + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(2, lines.Count); + Assert.AreEqual("Line 1", lines[0]); + Assert.AreEqual("Line 2", lines[1]); + } + + [TestMethod] + public void WrapRichText_EmptyFragments_HandlesGracefully() + { + RequireFont(SystemFontsEngine, "Calibri"); + RequireFont(SystemFontsEngine, "Arial"); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "Hello", + Font = new FontFormatBase { Family = "Arial", Size = 11 } + }, + new TextFragment + { + Text = "", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + } + }; + + // Act + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("Hello", lines[0]); + } + + [TestMethod] + public void WrapRichText_NullFragmentList_ReturnsEmptyLine() + { + RequireFont(SystemFontsEngine, "Calibri"); + + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + // Act + var lines = layout.WrapRichText(null, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual(string.Empty, lines[0]); + } + + #endregion + + #region Font Caching Tests + + [TestMethod] + public void WrapRichText_SameFontMultipleTimes_UsesCache() + { + // Arrange + var font = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, font); + var layout = new TextLayoutEngine(shaper); + + var fragments = new List + { + new TextFragment + { + Text = "First ", + Font = new FontFormatBase { Family = "Arial", Size = 11 } + }, + new TextFragment + { + Text = "second ", + Font = new FontFormatBase { Family = "Calibri", Size = 11 } + }, + new TextFragment + { + Text = "third", + Font = new FontFormatBase { Family = "Arial", Size = 11 } // Same as first + } + }; + + // Act - This should use cached shaper for Arial + var lines = layout.WrapRichText(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual("First second third", lines[0]); + // Note: We can't easily verify cache usage without exposing internals, + // but this test documents the expected behavior + } + + #endregion + + [TestMethod] + public void WrapText_Continous_Long_Word() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + + var longWord = "pellentesquer"; + + ITextShaper shaper = new TextShaper(SystemFontsEngine, font); + using var layoutEngine = new TextLayoutEngine(SystemFontsEngine, shaper); + var wrappedLines = layoutEngine.WrapText( + longWord, + 11f, + 54, + ShapingOptions.Full + ); + + Assert.AreEqual("pellentesqu", wrappedLines[0]); + Assert.AreEqual("er", wrappedLines[1]); + } + + [TestMethod] + public void WrapRichText_MeasureCorrectly() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + // Arrange + var font = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine,font); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + var fragments = new List + { + new TextFragment + { + Text = "value, 1", + Font = new FontFormatBase { Family = "Aptos Narrow", Size = 9 } + }, + }; + + // Act + var lines = layout.WrapRichTextLines(fragments, 1000); + + // Assert + Assert.AreEqual(1, lines.Count); + Assert.AreEqual(27.5712890625, lines[0].Width); + Assert.AreEqual("value, 1", lines[0].Text); + } + + [TestMethod] + public void VerifyWrappingSingleChar() + { + List lstOfRichText = new() { "SE/DKK" }; + RequireFont(SystemFontsEngine, "Aptos Narrow"); + + + var font1 = new FontFormatBase() + { + Family = "Aptos Narrow", + Size = 11, + SubFamily = FontSubFamily.Regular + }; + + var maxWidthPt = 31.8125234375d; + var gottenFont = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Regular); + var shaper = new TextShaper(SystemFontsEngine, gottenFont); + var layout = new TextLayoutEngine(SystemFontsEngine, shaper); + + List fragments = new List() { new TextFragment() { Font = font1, Text = lstOfRichText[0] } }; + + var wrappedLines = layout.WrapRichTextLines(fragments, maxWidthPt); + + Assert.AreEqual(0, wrappedLines[1].InternalLineFragments[0].StartIdx); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/MSTestSettings.cs b/src/EPPlus.Fonts.OpenType.Tests/MSTestSettings.cs new file mode 100644 index 0000000000..aaf278c844 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/EPPlus.Fonts.OpenType.Tests/PublicKey.snk b/src/EPPlus.Fonts.OpenType.Tests/PublicKey.snk new file mode 100644 index 0000000000..877ecc75f5 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType.Tests/PublicKey.snk differ diff --git a/src/EPPlus.Fonts.OpenType.Tests/Reading/GposReadingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Reading/GposReadingTests.cs new file mode 100644 index 0000000000..fb0b5758a8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Reading/GposReadingTests.cs @@ -0,0 +1,477 @@ +using EPPlus.Fonts.OpenType.FontResolver; +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.Reading +{ + [TestClass] + public class GposReadingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + + + [TestMethod] + public void ReadGposTable_Roboto() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + Assert.IsNotNull(font.GposTable, "Roboto should have GPOS table"); + + var gpos = font.GposTable; + + Assert.AreEqual((ushort)1, gpos.MajorVersion, "GPOS major version should be 1"); + Assert.IsNotNull(gpos.ScriptList, "GPOS should have ScriptList"); + Assert.IsNotNull(gpos.FeatureList, "GPOS should have FeatureList"); + Assert.IsNotNull(gpos.LookupList, "GPOS should have LookupList"); + } + + [TestMethod] + public void ReadGposTable_HasKernFeature() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + Assert.IsNotNull(gpos, "GPOS table should exist"); + + var kernFeature = gpos.FeatureList.FeatureRecords + .FirstOrDefault(f => f.FeatureTag.Value == "kern"); + + Assert.IsNotNull(kernFeature, "GPOS should have 'kern' feature"); + Assert.IsNotNull(kernFeature.FeatureTable, "kern feature should have FeatureTable"); + Assert.IsTrue(kernFeature.FeatureTable.LookupListIndices.Length > 0, + "kern feature should reference at least one lookup"); + } + + [TestMethod] + public void ReadGposTable_HasPairPosLookup() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + Assert.IsNotNull(gpos, "GPOS table should exist"); + + var pairPosLookup = gpos.LookupList.Lookups + .FirstOrDefault(l => l.LookupType == 2); + + Assert.IsNotNull(pairPosLookup, "GPOS should have Type 2 (PairPos) lookup"); + Assert.IsTrue(pairPosLookup.SubTables.Count > 0, + "PairPos lookup should have subtables"); + } + + [TestMethod] + public void ReadGposTable_PairPosFormat1() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var pairPosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 2); + + Assert.IsNotNull(pairPosLookup, "Need PairPos lookup for test"); + + var subtable = pairPosLookup.SubTables[0] as PairPosSubTableFormat1; + + Assert.IsNotNull(subtable, "First subtable should be PairPosSubTableFormat1"); + Assert.AreEqual((ushort)1, subtable.SubtableFormat, "Format should be 1"); + Assert.IsNotNull(subtable.Coverage, "Should have Coverage table"); + Assert.IsNotNull(subtable.PairSets, "Should have PairSets"); + Assert.IsTrue(subtable.PairSets.Count > 0, "Should have at least one PairSet"); + } + + [TestMethod] + public void ReadGposTable_FindKerningPair_ActualPairs() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + if (!font.CmapTable.TryGetGlyphId('A', out ushort aGlyph)) + { + Assert.Inconclusive("Could not get glyph ID for A"); + return; + } + + var gpos = font.GposTable; + var pairPosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 2); + Assert.IsNotNull(pairPosLookup, "Need PairPos lookup"); + + var subtable = pairPosLookup.SubTables[0] as PairPosSubTableFormat1; + Assert.IsNotNull(subtable, "Need PairPosSubTableFormat1"); + + bool found = subtable.TryGetPairAdjustment(aGlyph, 35, out var value1, out var value2); + + Assert.IsTrue(found, $"Should find kerning pair for A({aGlyph}) + glyph 35"); + Assert.IsNotNull(value1, "Value1 should exist"); + Assert.AreEqual(-61, value1.XAdvance, "Should have XAdvance = -61"); + + Debug.WriteLine($"✅ A + 35: XAdvance = {value1.XAdvance}"); + } + + [TestMethod] + public void SerializeCmapTable() + { + Debug.WriteLine("=== SerializeCmapTable ==="); + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("cmap"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var subtable = font.CmapTable.SubTables[0] as CmapSubtable4; + Debug.WriteLine($"IdDelta[3] = {subtable.IdDelta[3]}"); + + font.CmapTable.TryGetGlyphId('A', out ushort aGlyph); + Debug.WriteLine($"A = {aGlyph}"); + + var cmapBytes = font.CmapTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, cmapBytes?.Length); + CollectionAssert.AreEqual(originalBytes, cmapBytes); + } + + [TestMethod] + public void ReadGposTable_MultipleKerningPairs() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var pairPosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 2); + var subtable = pairPosLookup?.SubTables[0] as PairPosSubTableFormat1; + + Assert.IsNotNull(subtable, "Need PairPosSubTableFormat1"); + + var testPairs = new[] + { + (37, 35, -61), // A + glyph 35 + (37, 88, -17), // A + glyph 88 + (37, 91, -33), // A + glyph 91 + (58, 13, 20), // V + glyph 13 (adjusted from 14) + (58, 65, 17), // V + glyph 65 (adjusted from 66) + }; + + int foundCount = 0; + + foreach (var (first, second, expectedKern) in testPairs) + { + if (subtable.TryGetPairAdjustment((ushort)first, (ushort)second, out var val1, out var val2)) + { + foundCount++; + Assert.AreEqual(expectedKern, val1.XAdvance, + $"Pair {first}+{second} should have kerning {expectedKern}"); + Debug.WriteLine($"✅ {first}+{second}: XAdvance={val1.XAdvance}"); + } + else + { + Assert.Fail($"Should find pair {first}+{second}"); + } + } + + Assert.AreEqual(5, foundCount, "Should find all 5 test pairs"); + } + + [TestMethod] + public void ReadGposTable_HasSinglePosLookup() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + Assert.IsNotNull(gpos, "GPOS table should exist"); + + var singlePosLookup = gpos.LookupList.Lookups + .FirstOrDefault(l => l.LookupType == 1); + + if (singlePosLookup != null) + { + Assert.IsTrue(singlePosLookup.SubTables.Count > 0, + "SinglePos lookup should have subtables"); + Debug.WriteLine($"✅ Found SinglePos lookup with {singlePosLookup.SubTables.Count} subtable(s)"); + } + else + { + Assert.Inconclusive("Roboto does not have SinglePos (Type 1) lookups - this is OK"); + } + } + + [TestMethod] + public void ReadGposTable_SinglePosFormat1() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var singlePosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 1); + + if (singlePosLookup == null) + { + Assert.Inconclusive("Roboto does not have SinglePos lookups"); + return; + } + + var subtable = singlePosLookup.SubTables.FirstOrDefault() as SinglePosSubTableFormat1; + + if (subtable == null) + { + Assert.Inconclusive("First subtable is not Format 1"); + return; + } + + Assert.AreEqual((ushort)1, subtable.SubtableFormat, "Format should be 1"); + Assert.IsNotNull(subtable.Coverage, "Should have Coverage table"); + Assert.IsNotNull(subtable.Value, "Should have ValueRecord"); + + Debug.WriteLine($"✅ SinglePos Format 1:"); + Debug.WriteLine($" ValueFormat: 0x{subtable.ValueFormat:X4}"); + Debug.WriteLine($" XPlacement: {subtable.Value.XPlacement}"); + Debug.WriteLine($" YPlacement: {subtable.Value.YPlacement}"); + Debug.WriteLine($" XAdvance: {subtable.Value.XAdvance}"); + Debug.WriteLine($" YAdvance: {subtable.Value.YAdvance}"); + } + + [TestMethod] + public void ReadGposTable_SinglePosFormat2() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var singlePosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 1); + + if (singlePosLookup == null) + { + Assert.Inconclusive("Roboto does not have SinglePos lookups"); + return; + } + + var subtable = singlePosLookup.SubTables + .OfType() + .FirstOrDefault(); + + if (subtable == null) + { + Assert.Inconclusive("No Format 2 subtables found"); + return; + } + + Assert.AreEqual((ushort)2, subtable.SubtableFormat, "Format should be 2"); + Assert.IsNotNull(subtable.Coverage, "Should have Coverage table"); + Assert.IsNotNull(subtable.Values, "Should have ValueRecords array"); + Assert.AreEqual(subtable.ValueCount, subtable.Values.Length, + "ValueCount should match array length"); + + Debug.WriteLine($"✅ SinglePos Format 2:"); + Debug.WriteLine($" ValueFormat: 0x{subtable.ValueFormat:X4}"); + Debug.WriteLine($" ValueCount: {subtable.ValueCount}"); + Debug.WriteLine($" First value - XPlacement: {subtable.Values[0].XPlacement}, YPlacement: {subtable.Values[0].YPlacement}"); + } + + [TestMethod] + public void ReadGposTable_SinglePosTryGetAdjustment() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var singlePosLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 1); + + if (singlePosLookup == null) + { + Assert.Inconclusive("Roboto does not have SinglePos lookups"); + return; + } + + var subtableFormat1 = singlePosLookup.SubTables.OfType().FirstOrDefault(); + var subtableFormat2 = singlePosLookup.SubTables.OfType().FirstOrDefault(); + + bool foundAdjustment = false; + + if (subtableFormat1 != null) + { + for (ushort glyphId = 1; glyphId < 100; glyphId++) + { + if (subtableFormat1.TryGetAdjustment(glyphId, out var value)) + { + Debug.WriteLine($"✅ Format 1: Glyph {glyphId} has adjustment: XAdv={value.XAdvance}, YAdv={value.YAdvance}"); + foundAdjustment = true; + break; + } + } + } + + if (subtableFormat2 != null && !foundAdjustment) + { + for (ushort glyphId = 1; glyphId < 100; glyphId++) + { + if (subtableFormat2.TryGetAdjustment(glyphId, out var value)) + { + Debug.WriteLine($"✅ Format 2: Glyph {glyphId} has adjustment: XAdv={value.XAdvance}, YAdv={value.YAdvance}"); + foundAdjustment = true; + break; + } + } + } + + if (!foundAdjustment) + { + Assert.Inconclusive("No adjustments found in coverage - this is OK if font doesn't use SinglePos heavily"); + } + } + + [TestMethod] + public void ReadGposTable_HasMarkToBaseLookup() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + Assert.IsNotNull(gpos, "GPOS table should exist"); + + var markToBaseLookup = gpos.LookupList.Lookups + .FirstOrDefault(l => l.LookupType == 4); + + if (markToBaseLookup != null) + { + Assert.IsTrue(markToBaseLookup.SubTables.Count > 0, + "MarkToBase lookup should have subtables"); + Debug.WriteLine($"✅ Found MarkToBase lookup with {markToBaseLookup.SubTables.Count} subtable(s)"); + } + else + { + Assert.Inconclusive("Roboto does not have MarkToBase (Type 4) lookups - this is OK"); + } + } + + [TestMethod] + public void ReadGposTable_MarkToBaseFormat1() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var markToBaseLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 4); + + if (markToBaseLookup == null) + { + Assert.Inconclusive("Roboto does not have MarkToBase lookups"); + return; + } + + var subtable = markToBaseLookup.SubTables.FirstOrDefault() as MarkToBaseSubTableFormat1; + + if (subtable == null) + { + Assert.Inconclusive("First subtable is not MarkToBaseSubTableFormat1"); + return; + } + + Assert.AreEqual((ushort)1, subtable.SubtableFormat, "Format should be 1"); + Assert.IsNotNull(subtable.MarkCoverage, "Should have MarkCoverage table"); + Assert.IsNotNull(subtable.BaseCoverage, "Should have BaseCoverage table"); + Assert.IsNotNull(subtable.MarkArray, "Should have MarkArray"); + Assert.IsNotNull(subtable.BaseArray, "Should have BaseArray"); + Assert.IsTrue(subtable.MarkClassCount > 0, "Should have at least one mark class"); + + Debug.WriteLine($"✅ MarkToBase Format 1:"); + Debug.WriteLine($" MarkClassCount: {subtable.MarkClassCount}"); + Debug.WriteLine($" MarkArray count: {subtable.MarkArray.MarkCount}"); + Debug.WriteLine($" BaseArray count: {subtable.BaseArray.BaseCount}"); + } + + [TestMethod] + public void ReadGposTable_MarkToBaseTryGetAttachment() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var markToBaseLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 4); + + if (markToBaseLookup == null) + { + Assert.Inconclusive("Roboto does not have MarkToBase lookups"); + return; + } + + var subtable = markToBaseLookup.SubTables.FirstOrDefault() as MarkToBaseSubTableFormat1; + + if (subtable == null) + { + Assert.Inconclusive("No MarkToBase subtable found"); + return; + } + + bool foundAttachment = false; + + for (ushort markGlyph = 1; markGlyph < 100 && !foundAttachment; markGlyph++) + { + if (subtable.MarkCoverage.IsCovered(markGlyph)) + { + for (ushort baseGlyph = 1; baseGlyph < 100; baseGlyph++) + { + if (subtable.BaseCoverage.IsCovered(baseGlyph)) + { + if (subtable.TryGetAttachment(markGlyph, baseGlyph, out var markAnchor, out var baseAnchor)) + { + Debug.WriteLine($"✅ Found attachment:"); + Debug.WriteLine($" Mark glyph: {markGlyph}"); + Debug.WriteLine($" Base glyph: {baseGlyph}"); + Debug.WriteLine($" Mark anchor: ({markAnchor.XCoordinate}, {markAnchor.YCoordinate})"); + Debug.WriteLine($" Base anchor: ({baseAnchor.XCoordinate}, {baseAnchor.YCoordinate})"); + foundAttachment = true; + break; + } + } + } + } + } + + if (!foundAttachment) + { + Assert.Inconclusive("No attachments found - this is OK if font doesn't use MarkToBase heavily"); + } + } + + [TestMethod] + public void ReadGposTable_MarkToBaseWithAccentedCharacters() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular, ignoreCache: true); + + var gpos = font.GposTable; + var markToBaseLookup = gpos.LookupList.Lookups.FirstOrDefault(l => l.LookupType == 4); + + if (markToBaseLookup == null) + { + Assert.Inconclusive("Roboto does not have MarkToBase lookups"); + return; + } + + var subtable = markToBaseLookup.SubTables.FirstOrDefault() as MarkToBaseSubTableFormat1; + + if (subtable == null) + { + Assert.Inconclusive("No MarkToBase subtable found"); + return; + } + + if (font.CmapTable.TryGetGlyphId('e', out ushort eGlyph)) + { + Debug.WriteLine($"'e' = glyph {eGlyph}"); + + if (font.CmapTable.TryGetGlyphId('\u0301', out ushort acuteGlyph)) + { + Debug.WriteLine($"Combining acute = glyph {acuteGlyph}"); + + if (subtable.TryGetAttachment(acuteGlyph, eGlyph, out var markAnchor, out var baseAnchor)) + { + Debug.WriteLine($"✅ Found 'é' attachment:"); + Debug.WriteLine($" Mark anchor: ({markAnchor.XCoordinate}, {markAnchor.YCoordinate})"); + Debug.WriteLine($" Base anchor: ({baseAnchor.XCoordinate}, {baseAnchor.YCoordinate})"); + } + else + { + Debug.WriteLine("No attachment found for 'e' + acute"); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Reading/TtfReadingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Reading/TtfReadingTests.cs new file mode 100644 index 0000000000..511dff8e7d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Reading/TtfReadingTests.cs @@ -0,0 +1,277 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/22/2025 EPPlus Software AB TTF reading tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontResolver; +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tests.Reading +{ + [TestClass] + public sealed class TtfReadingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void ReadRobotoRegularTtf() + { + OpenTypeFont? font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + Assert.IsNotNull(font); + var cmap = font.CmapTable; + Assert.AreEqual("Roboto", font.FullName); + Assert.AreEqual("Regular", font.SubFamily); + Assert.AreEqual(1295, font.GlyfTable.Glyphs.Count); + } + + [TestMethod] + public void ReadRobotoBoldTtf() + { + Stopwatch sw = Stopwatch.StartNew(); + sw.Start(); + OpenTypeFont? font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Bold); + sw.Stop(); + var ms = sw.ElapsedMilliseconds; + Assert.IsNotNull(font); + Assert.AreEqual("Roboto Bold", font.FullName); + Assert.AreEqual("Bold", font.SubFamily); + } + + [TestMethod] + public void ReadSourceSans3Otf() + { + OpenTypeFont? font = TestFolderEngine.LoadFont("Source Sans 3", FontSubFamily.Regular); + Assert.IsNotNull(font); + Assert.AreEqual("Source Sans 3", font.FullName); + Assert.AreEqual("Regular", font.SubFamily); + } + + struct LicenseDataHolder() + { + public string? FontName; + public ushort LicenseType; + public string? LTypeString; + } + + /// + /// Indicates font embedding licensing rights for the font. The interpretation of flags is as follows: + /// 0: Installable embedding: the font may be embedded, and may be permanently installed for use on a remote systems, or for use by other users. + /// 2: Restricted License embedding: the font must not be modified, embedded or exchanged in any manner without first obtaining explicit permission of the legal owner. + /// 4: Preview & Print embedding: the font may be embedded, and may be temporarily loaded on other systems for purposes of viewing or printing the document. Documents containing Preview & Print fonts must be opened "read-only"; no edits can be applied to the document. + /// 8: Editable embedding: the font may be embedded, and may be temporarily loaded on other systems. As with Preview & Print embedding, documents containing Editable fonts may be opened for reading. In addition, editing is permitted, including ability to format new text using the embedded font, and changes may be saved. + /// + string GetFsString(ushort fsId) + { + switch (fsId) + { + case 0: + return "Installable Embedding"; + case 2: + return "Restricted Licence Embedding"; + case 4: + return "Preview & Print Embedding"; + case 8: + return "Editable Embedding"; + default: + return $"UNKNOWN VALUE: '{fsId}' POTENTIALLY CORRUPT FONT"; + } + } + + [TestMethod] + public void ReadTccGothic() + { + OpenTypeFont? font = TestFolderEngine.LoadFont("BIZ UDGothic", FontSubFamily.Bold); + + Assert.IsNotNull(font); + Assert.AreEqual("BIZ UDGothic Bold", font.FullName); + Assert.AreEqual("Bold", font.SubFamily); + } + + [TestMethod] + public void ReadGsubTable() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var gSub = font.GsubTable; + Assert.IsNotNull(gSub); + } + + [TestMethod] + public void ReadSixFonts() + { + RequireFont(SystemFontsEngine, "Aptos Narrow"); + RequireFont(SystemFontsEngine, "Times New Roman"); + RequireFont(SystemFontsEngine, "Calibri", FontSubFamily.Italic); + + OpenTypeFont ? gothic = TestFolderEngine.LoadFont("BIZ UDGothic", FontSubFamily.Bold); + OpenTypeFont? calibri = SystemFontsEngine.LoadFont("Calibri", FontSubFamily.Italic); + OpenTypeFont? aptos = SystemFontsEngine.LoadFont("Aptos Narrow", FontSubFamily.Bold); + OpenTypeFont? timesNewRoman = SystemFontsEngine.LoadFont("Times New Roman", FontSubFamily.Regular); + OpenTypeFont? SS3 = TestFolderEngine.LoadFont("Source Sans 3", FontSubFamily.Regular); + + Assert.IsNotNull(gothic); + Assert.AreEqual("BIZ UDGothic Bold", gothic.FullName); + Assert.AreEqual("Bold", gothic.SubFamily); + + Assert.IsNotNull(calibri); + Assert.AreEqual("Calibri Italic", calibri.FullName); + Assert.AreEqual("Italic", calibri.SubFamily); + + Assert.IsNotNull(aptos); + Assert.AreEqual("Aptos Narrow Bold", aptos.FullName); + Assert.AreEqual("Bold", aptos.SubFamily); + + Assert.IsNotNull(timesNewRoman); + Assert.AreEqual("Times New Roman", timesNewRoman.FullName); + Assert.AreEqual("Regular", timesNewRoman.SubFamily); + + Assert.IsNotNull(SS3); + Assert.AreEqual("Source Sans 3", SS3.FullName); + Assert.AreEqual("Regular", SS3.SubFamily); + } + + [TestMethod] + public void ReadAllOTFFonts() + { + List allFontsList = OpenTypeFonts.GetAllBaseFontData(FontFolders, true, Scanner.FontFormat.Otf); + + List dataHolder = new List(); + + for (int i = 0; i < allFontsList.Count; i++) + { + LicenseDataHolder dataHolderItem = new LicenseDataHolder() + { + FontName = allFontsList[i].FullName, + LicenseType = allFontsList[i].Os2Table.fsType, + LTypeString = GetFsString(allFontsList[i].Os2Table.fsType) + }; + + dataHolder.Add(dataHolderItem); + Assert.AreEqual(Scanner.FontFormat.Otf, allFontsList[i].Format); + } + + var fontsThatCannotBeEmbedded = dataHolder.Where(x => x.LicenseType == 2); + + Assert.AreEqual(0, fontsThatCannotBeEmbedded.Count()); + } + + [TestMethod] + public void ReadAllTestTTFFontsAndVerifyUseIsOkay() + { + List allFontsList = OpenTypeFonts.GetAllBaseFontData(FontFolders, false, Scanner.FontFormat.Ttf); + + List dataHolder = new List(); + + for (int i = 0; i < allFontsList.Count; i++) + { + LicenseDataHolder dataHolderItem = new LicenseDataHolder() + { + FontName = allFontsList[i].FullName, + LicenseType = allFontsList[i].Os2Table.fsType, + LTypeString = GetFsString(allFontsList[i].Os2Table.fsType) + }; + + dataHolder.Add(dataHolderItem); + Assert.AreEqual(Scanner.FontFormat.Ttf, allFontsList[i].Format); + } + + //Ensure all fonts in the font folder are free to install/use + var fontsThatAreInstallableEmbedded = dataHolder.Where(x => x.LicenseType == 0); + + Assert.AreEqual(fontsThatAreInstallableEmbedded.Count(), dataHolder.Count()); + } + + [TestMethod, Ignore("This test takes a long time and should not run in quick regression tests")] + public void ReadAllTTFFonts() + { + List allFontsList = OpenTypeFonts.GetAllBaseFontData(FontFolders, true, Scanner.FontFormat.Ttf); + + List dataHolder = new List(); + + for (int i = 0; i < allFontsList.Count; i++) + { + LicenseDataHolder dataHolderItem = new LicenseDataHolder() + { + FontName = allFontsList[i].FullName, + LicenseType = allFontsList[i].Os2Table.fsType, + LTypeString = GetFsString(allFontsList[i].Os2Table.fsType) + }; + + dataHolder.Add(dataHolderItem); + Assert.AreEqual(Scanner.FontFormat.Ttf, allFontsList[i].Format); + } + + var fontsThatCannotBeEmbedded = dataHolder.Where(x => x.LicenseType == 2); + + Assert.AreEqual(0, fontsThatCannotBeEmbedded.Count()); + } + + [TestMethod, Ignore("This test takes a long time and should not run in quick regression tests")] + public void ReadAllFonts() + { + var sw = new Stopwatch(); + sw.Start(); + List allFontsList = OpenTypeFonts.GetAllBaseFontData(FontFolders, true); + sw.Stop(); + + Trace.WriteLine(sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestWrapText() + { + string fontName = "Aptos Narrow"; + string testStr = "hello the most"; + double fontSize = 11.0d; + double MaxPixelWidth = 52d; + + MeasurementFont mf = new MeasurementFont() + { + FontFamily = fontName, + Size = (float)fontSize, + Style = MeasurementFontStyles.Regular + }; + + var fontMeasurer = SystemFontsEngine.GetTextLayoutEngineForFont(mf); + var strings = fontMeasurer.WrapText(testStr, mf.Size, MaxPixelWidth); + + Assert.AreEqual("hello the", strings[0]); + Assert.AreEqual("most", strings[1]); + } + + [TestMethod] + public void TestWrapTextWhenLineBreaks() + { + string fontName = "Aptos Narrow"; + string testStr = "hello\r\n the\r\n most"; + double fontSize = 11.0d; + double MaxPixelWidth = 52d; + + RequireFont(SystemFontsEngine, fontName); + + MeasurementFont mf = new MeasurementFont() + { + FontFamily = fontName, + Size = (float)fontSize, + Style = MeasurementFontStyles.Regular + }; + + var fontMeasurer = SystemFontsEngine.GetTextLayoutEngineForFont(mf); + var strings = fontMeasurer.WrapText(testStr, mf.Size, MaxPixelWidth); + + Assert.AreEqual("hello", strings[0]); + Assert.AreEqual(" the", strings[1]); + Assert.AreEqual(" most", strings[2]); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Reading/VerticalTextTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Reading/VerticalTextTests.cs new file mode 100644 index 0000000000..a09ae4c928 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Reading/VerticalTextTests.cs @@ -0,0 +1,71 @@ +using Microsoft.ApplicationInsights.DataContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Reading +{ + [TestClass] + public class VerticalTextTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + + [TestMethod] + public void TestVerticalMetrics_Vhea() + { + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + Assert.IsNotNull(font); + var vhea = font.VheaTable; + Assert.IsNotNull(vhea, "vhea table should be present in a CJK font."); + // Basic sanity checks on vhea values + Assert.IsTrue(vhea.Ascent > 0, "Ascent should be positive."); + Assert.IsTrue(vhea.AdvanceHeightMax > 0, "AdvanceHeightMax should be positive."); + Assert.IsTrue( + vhea.NumberOfVMetrics <= font.MaxpTable.numGlyphs, + $"NumberOfVMetrics ({vhea.NumberOfVMetrics}) exceeds numGlyphs ({font.MaxpTable.numGlyphs})."); + } + + [TestMethod] + public void TestVerticalMetrics_Vmtx() + { + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + Assert.IsNotNull(font); + + var vhea = font.VheaTable; + var vmtx = font.VmtxTable; + Assert.IsNotNull(vmtx, "vmtx table should be present in a CJK font."); + + // VMetrics count must match vhea.NumberOfVMetrics + Assert.AreEqual( + (int)vhea.NumberOfVMetrics, + vmtx.VMetrics.Count, + $"VMetrics.Count ({vmtx.VMetrics.Count}) should match vhea.NumberOfVMetrics ({vhea.NumberOfVMetrics})."); + + // Total glyph coverage must equal maxp.numGlyphs + int totalCoverage = vmtx.VMetrics.Count + vmtx.TopSideBearings.Count; + Assert.AreEqual( + font.MaxpTable.numGlyphs, + totalCoverage, + $"VMetrics ({vmtx.VMetrics.Count}) + TopSideBearings ({vmtx.TopSideBearings.Count}) should equal numGlyphs ({font.MaxpTable.numGlyphs})."); + + // Majority of advance heights should be > 0 (some glyphs like .notdef may be 0) + int zeroCount = 0; + for (int i = 0; i < vmtx.VMetrics.Count; i++) + { + if (vmtx.VMetrics[i].AdvanceHeight == 0) + zeroCount++; + } + Assert.IsTrue( + zeroCount < vmtx.VMetrics.Count / 2, + $"Too many zero AdvanceHeights: {zeroCount} out of {vmtx.VMetrics.Count}."); + + // GetAdvanceHeight should work for first and last glyph + Assert.IsTrue(vmtx.GetAdvanceHeight(0) > 0, "GetAdvanceHeight(0) should be > 0."); + Assert.IsTrue( + vmtx.GetAdvanceHeight((ushort)(font.MaxpTable.numGlyphs - 1)) > 0, + "GetAdvanceHeight for last glyph should be > 0."); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Regression/RegressionTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Regression/RegressionTests.cs new file mode 100644 index 0000000000..9b83b6dada --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Regression/RegressionTests.cs @@ -0,0 +1,277 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/22/2025 EPPlus Software AB Regression tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontCache; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; + +namespace EPPlus.Fonts.OpenType.Tests.Regression +{ + /// + /// Tests for specific bugs that have been found and fixed. + /// Each test documents a bug to prevent regression. + /// + [TestClass] + public class RegressionTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void Bug_20251222_CircularLigatureDependency_Roboto() + { + // BUG: ffi ligature referenced fi ligature as component (GID >= 400) + // This caused circular dependencies in subsetting + // + // Original structure in Roboto: + // fi-ligature (444): components = [i(77), mysterious-447] + // ffi-ligature (446): components = [f(74), i(77), fi-ligature(444)] + // ff-ligature (443): components = [f(74), 449] + // + // CAUSE: Discovery phase included ligatures as components, creating cycles + // FIX: Ignore components with GID >= 400 (ligature glyphs) in both + // Discovery and Rewrite phases + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("ffi"); + + SaveFont("regression_ffi_circular.ttf", subset); + + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + Assert.IsNotNull(parsed.GsubTable); + + int ligCount = FontTestHelper.CountLigatures(parsed); + Assert.IsTrue(ligCount > 0, "ffi ligature should exist after subsetting"); + + FontTestHelper.AssertFontValid(parsed); + } + + [TestMethod] + public void Bug_20251222_AbcSubset_TooManyGlyphs() + { + // BUG: Subsetting 'abc' resulted in 28 glyphs instead of ~10 + // CAUSE: Ligature discovery included all f-ligatures (fi, ff, fl, ffi, ffl) + // even though 'abc' doesn't contain 'f' + // ROOT CAUSE: Discovery didn't validate that base character components existed + // FIX: Only include ligatures where ALL base character components (GID < 400) + // exist in the subset + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset(new[] { 'a', 'b', 'c' }); + + SaveFont("regression_abc_glyphs.ttf", subset); + + Assert.IsTrue(subset.MaxpTable.numGlyphs >= 5 && subset.MaxpTable.numGlyphs <= 15, + $"Expected 5-15 glyphs for abc, got {subset.MaxpTable.numGlyphs}"); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.AreEqual(0, ligCount, "abc should have no ligatures"); + } + + [TestMethod] + public void Bug_20251222_Fiffig_LostLigatures_AfterAbcFix() + { + // BUG: After fixing 'abc' bug, 'fiffig' lost all ligatures + // CAUSE: Fix was too aggressive - also filtered out valid ligatures + // FIX: Corrected logic to only check base components (GID < 400) + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("fiffig"); + + SaveFont("regression_fiffig_ligatures.ttf", subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.AreEqual(3, ligCount, "fiffig should have fi, ff, ffi ligatures"); + + FontTestHelper.AssertFontValid(subset); + } + + [TestMethod] + public void Bug_20251222_FeaturePointsToInvalidLookup() + { + // BUG: After subsetting, features pointed to non-existent lookup indices + // CAUSE: Lookups were removed during subsetting but feature indices weren't remapped + // FIX: FeatureListTable.Rewrite now uses lookupMap to remap indices + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("fiffig"); + + SaveFont("regression_feature_lookup.ttf", subset); + + if (subset.GsubTable?.FeatureList?.FeatureRecords != null) + { + int lookupCount = subset.GsubTable.LookupList?.Lookups?.Count ?? 0; + + foreach (var feature in subset.GsubTable.FeatureList.FeatureRecords) + { + if (feature.FeatureTable?.LookupListIndices != null) + { + foreach (var idx in feature.FeatureTable.LookupListIndices) + { + Assert.IsTrue(idx < lookupCount, + $"Feature {feature.FeatureTag} points to invalid lookup {idx} (max: {lookupCount - 1})"); + } + } + } + } + } + + [TestMethod] + public void Bug_20251222_LigatureComponentRewrite_WrongDictionary() + { + // BUG: LigatureSetTable.Rewrite used wrong dictionary for component mapping + // CAUSE: Used oldLig.Components instead of looking up in OldToNewGlyphId + // SYMPTOM: Components weren't remapped to new GIDs + // FIX: Properly lookup each component in OldToNewGlyphId dictionary + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("fi"); + + SaveFont("regression_ligature_components.ttf", subset); + + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + int ligCount = FontTestHelper.CountLigatures(parsed); + Assert.IsTrue(ligCount >= 1, "Should have fi ligature"); + + FontTestHelper.AssertFontValid(parsed); + } + + [TestMethod] + public void Bug_20251222_ValidationCrash_NullRawData() + { + // BUG: TableRecordsValidator crashed with NullReferenceException on subset fonts + // CAUSE: Validator tried to access font.RawData which is null for in-memory fonts + // LINE: TableRecordsValidator.cs line 111: byte[] fontData = (byte[])font.RawData.Clone() + // FIX: Check if RawData is null before accessing, skip checksum validation for in-memory fonts + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("f"); + + SaveFont("regression_validation_rawdata.ttf", subset); + + FontTestHelper.AssertFontValid(subset); + + Assert.IsNotNull(subset); + Assert.IsTrue(subset.MaxpTable.numGlyphs > 0); + } + + [TestMethod] + public void Bug_20251222_ValidationCrash_FileLengthZero() + { + // BUG: TableRecordsValidator failed with "Font file length could not be determined or is zero" + // CAUSE: font.FileLength returned 0 for in-memory fonts (no underlying stream) + // FIX: Calculate fileLength from TableRecords if FileLength property is <= 0 + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("fl"); + + SaveFont("regression_validation_filelength.ttf", subset); + + FontTestHelper.AssertFontValid(subset); + + Assert.IsNotNull(subset); + } + + [TestMethod] + public void Bug_20251222_MissingCoverageInitialization() + { + // BUG: Coverage table and SubtableFormat not initialized in ligature rewrite + // CAUSE: Missing initialization in LigatureSubstSubTable.Rewrite + // SYMPTOM: Serialization failed or produced invalid fonts + // FIX: Initialize Coverage.SubstFormat = 1 and newSubTable.SubstFormat = 1 + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("office"); + + SaveFont("regression_coverage_init.ttf", subset); + + var bytes = subset.Serialize(); + Assert.IsNotNull(bytes); + Assert.IsTrue(bytes.Length > 0); + + var parsed = new OpenTypeFont(bytes); + Assert.IsNotNull(parsed); + + FontTestHelper.AssertFontValid(parsed); + } + + [TestMethod] + public void Bug_20251222_EmptySubset_ShouldThrow() + { + // BUG: CreateSubset with empty string didn't throw exception + // EXPECTED: ArgumentException for empty input + // FIX: Added validation to throw ArgumentException if usedChars is empty + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + + Assert.ThrowsException(() => font.CreateSubset("")); + Assert.ThrowsException(() => font.CreateSubset((char[])null)); + } + + [TestMethod] + public void Bug_20251222_CompoundLigatureComponents() + { + // BUG: Roboto's ligature definitions used compound structures where + // ligatures referenced other ligatures as components + // EXAMPLE: + // fi-ligature (444): [i, mysterious-447] where 447 is another ligature + // ffi-ligature (446): [f, i, fi-ligature(444)] + // FIX: Ignore ligature components (GID >= 400) in both Discovery and Rewrite + // RESULT: Simplified component lists (ffi = [f, f, i] instead of [f, i, fi]) + // DATE: 2025-12-22 + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var subset = font.CreateSubset("fiffig"); + + SaveFont("regression_compound_components.ttf", subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.AreEqual(3, ligCount); + + FontTestHelper.AssertFontValid(subset); + } + + [TestMethod] + public void GetFromCacheBoldItalicShouldWork() + { + MeasurementFont boldItalic = new MeasurementFont() + { + FontFamily = "Roboto", + Size = 11f, + Style = MeasurementFontStyles.Bold | MeasurementFontStyles.Italic + }; + + var first = TestFolderEngine.LoadFont(boldItalic.FontFamily, FontSubFamily.BoldItalic); + var second = TestFolderEngine.LoadFont(boldItalic.FontFamily, FontSubFamily.BoldItalic); + + Assert.IsNotNull(first); + Assert.AreSame(first, second, "Second load should return the cached instance"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Scripts/UnicodeScriptClassifierTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Scripts/UnicodeScriptClassifierTests.cs new file mode 100644 index 0000000000..4d7e828e98 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Scripts/UnicodeScriptClassifierTests.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/20/2026 EPPlus Software AB Boundary tests for binary-search classifier + *************************************************************************************************/ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Tests +{ + /// + /// Boundary tests for . + /// + /// We do not test every script's content — that would be source-code duplication, since + /// the classifier is effectively a static lookup table. Instead we verify that the binary + /// search treats range endpoints as inclusive on both sides, which protects against + /// off-by-one bugs if the algorithm is rewritten. + /// + /// Functional correctness of the table is exercised indirectly by higher-level tests + /// (DefaultFontProvider routing emoji to Noto Emoji, etc.). + /// + [TestClass] + public class UnicodeScriptClassifierTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void Classify_CodePointOnRangeStart_IsInclusive() + { + // U+4E00 is the first code point of the CJK Unified Ideographs main block. + // If the binary search treats Start as exclusive, this returns Unknown. + Assert.AreEqual(UnicodeScript.Han, UnicodeScriptClassifier.OfCodePoint(0x4E00)); + } + + [TestMethod] + public void Classify_CodePointOnRangeEnd_IsInclusive() + { + // U+9FFF is the last code point of the CJK Unified Ideographs main block. + // If the binary search treats End as exclusive, this returns Unknown. + Assert.AreEqual(UnicodeScript.Han, UnicodeScriptClassifier.OfCodePoint(0x9FFF)); + } + + [TestMethod] + public void Classify_CodePointJustOutsideRange_ReturnsUnknown() + { + // U+036F is the last Combining Diacritical Mark; U+0370 starts Greek. + // Verifies that the classifier does not over-shoot a range on the high side. + Assert.AreEqual(UnicodeScript.Unknown, UnicodeScriptClassifier.OfCodePoint(0x036F)); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Serialization/CmapSerializationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Serialization/CmapSerializationTests.cs new file mode 100644 index 0000000000..1a58700956 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Serialization/CmapSerializationTests.cs @@ -0,0 +1,61 @@ +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Serialization +{ + [TestClass] + public class CmapSerializationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void SerializeCmapTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("cmap"); + + var font = TestFolderEngine.LoadFont("Roboto"); + var cmapBytes = font.CmapTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, cmapBytes?.Length); + CollectionAssert.AreEqual(originalBytes, cmapBytes); + } + + [TestMethod] + public void SerializeCmapTable_Format12() + { + var font = TestFolderEngine.LoadFont("Noto Emoji"); + + // Ta unique chars from the originalfonts cmap (format 4 + 12) + var allCodePoints = new HashSet(); + foreach (var sub in font.CmapTable.SubTables) + { + if (sub.Format == 14) continue; // skip VS + var map = sub.GetGlyphMappings().CharCodeToGlyphIndex; + foreach (var cp in map.Keys) + allCodePoints.Add(cp); + } + + // re-serialize + var bytes = font.Serialize(); + var tempFont = new OpenTypeFont(bytes); + + // Check that ALL original chars are still there + foreach (uint cp in allCodePoints) + { + ushort gid1, gid2; + bool has1 = font.CmapTable.TryGetGlyphId(cp, out gid1); + bool has2 = tempFont.CmapTable.TryGetGlyphId(cp, out gid2); + + Assert.IsTrue(has1 == has2, $"Code point U+{cp:X4} lost after roundtrip"); + if (has1) + Assert.AreEqual(gid1, gid2); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Serialization/CoreTableSerializationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Serialization/CoreTableSerializationTests.cs new file mode 100644 index 0000000000..ac401899b8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Serialization/CoreTableSerializationTests.cs @@ -0,0 +1,102 @@ +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Serialization +{ + [TestClass] + public class CoreTableSerializationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void SerializeHeadTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("head"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var headBytes = font?.HeadTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, headBytes?.Length); + CollectionAssert.AreEqual(originalBytes, headBytes); + } + + [TestMethod] + public void SerializeMaxpTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("maxp"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var maxpBytes = font?.MaxpTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, maxpBytes?.Length); + CollectionAssert.AreEqual(originalBytes, maxpBytes); + } + + [TestMethod] + public void SerializeHheaTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("hhea"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var hheaBytes = font?.HheaTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, hheaBytes?.Length); + CollectionAssert.AreEqual(originalBytes, hheaBytes); + } + + [TestMethod] + public void SerializePostTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolders, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("post"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var postBytes = font?.PostTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, postBytes?.Length); + CollectionAssert.AreEqual(originalBytes, postBytes); + } + + [TestMethod] + public void SerializeNameTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("name"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var nameBytes = font?.NameTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, nameBytes?.Length); + CollectionAssert.AreEqual(originalBytes, nameBytes); + } + + [TestMethod] + [DataRow("Roboto", FontSubFamily.Regular, 96)] + [DataRow("Roboto", FontSubFamily.Italic, 96)] + [DataRow("EB Garamond", FontSubFamily.Regular, 100)] + [DataRow("Mulish", FontSubFamily.Regular, 100)] + public void SerializeOs2Table(string fontName, FontSubFamily subFamily, int expectedLength) + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, fontName, subFamily); + var originalBytes = ffi.GetTableBytes("OS/2"); + + var font = TestFolderEngine.LoadFont(fontName, subFamily); + var os2Bytes = font?.Os2Table.Serialize(font); + + Assert.AreEqual(expectedLength, os2Bytes?.Length); + if (expectedLength > originalBytes.Length) + { + os2Bytes = os2Bytes?.Take(originalBytes.Length).ToArray(); + } + CollectionAssert.AreEqual(originalBytes, os2Bytes); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Serialization/GPosSerializationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Serialization/GPosSerializationTests.cs new file mode 100644 index 0000000000..8633c1ad54 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Serialization/GPosSerializationTests.cs @@ -0,0 +1,755 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/13/2026 EPPlus Software AB GPOS serialization tests (semantic validation) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tests.Serialization +{ + /// + /// Tests for GPOS table serialization with semantic validation. + /// These tests verify that positioning data survives roundtrip serialization, + /// without requiring byte-perfect output (Format 2 may be expanded to Format 1, etc.) + /// + [TestClass] + public class GposSerializationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + #region Helper Classes for .NET 3.5 Compatibility + + private class GlyphPair + { + public ushort FirstGlyph { get; set; } + public ushort SecondGlyph { get; set; } + + public GlyphPair(ushort first, ushort second) + { + FirstGlyph = first; + SecondGlyph = second; + } + + public override bool Equals(object obj) + { + var other = obj as GlyphPair; + if (other == null) return false; + return FirstGlyph == other.FirstGlyph && SecondGlyph == other.SecondGlyph; + } + + public override int GetHashCode() + { + return (FirstGlyph << 16) | SecondGlyph; + } + } + + private class AnchorPointPair + { + public short MarkAnchorX { get; set; } + public short MarkAnchorY { get; set; } + public short BaseAnchorX { get; set; } + public short BaseAnchorY { get; set; } + } + + private class SinglePosValue + { + public short XPlacement { get; set; } + public short YPlacement { get; set; } + public short XAdvance { get; set; } + public short YAdvance { get; set; } + } + + #endregion + + [TestMethod] + public void Diagnose_SerializedFontOffsets() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + Debug.WriteLine("=== ORIGINAL TABLE RECORDS ==="); + foreach (var kvp in font.TableRecords) + { + Debug.WriteLine(string.Format("{0}: Offset={1}, Length={2}", + kvp.Key, kvp.Value.Offset, kvp.Value.Length)); + } + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + + Debug.WriteLine(string.Format("\n=== SERIALIZED FONT: {0} bytes ===", bytes.Length)); + + using (var ms = new MemoryStream(bytes)) + using (var reader = new FontsBinaryReader(ms)) + { + reader.BaseStream.Position = 0; + uint sfntVersion = reader.ReadUInt32BigEndian(); + ushort numTables = reader.ReadUInt16BigEndian(); + reader.ReadUInt16BigEndian(); + reader.ReadUInt16BigEndian(); + reader.ReadUInt16BigEndian(); + + Debug.WriteLine(string.Format("\nsfntVersion: 0x{0:X8}", sfntVersion)); + Debug.WriteLine(string.Format("numTables: {0}", numTables)); + + Debug.WriteLine("\n=== SERIALIZED TABLE RECORDS ==="); + for (int i = 0; i < numTables; i++) + { + byte[] tagBytes = reader.ReadBytes(4); + string tag = System.Text.Encoding.ASCII.GetString(tagBytes); + uint checksum = reader.ReadUInt32BigEndian(); + uint offset = reader.ReadUInt32BigEndian(); + uint length = reader.ReadUInt32BigEndian(); + + string status = offset + length > bytes.Length ? " *** INVALID: extends beyond file!" : ""; + Debug.WriteLine(string.Format("{0}: Offset={1}, Length={2}{3}", tag, offset, length, status)); + } + } + } + + #region Structure Preservation Tests + + [TestMethod] + public void SerializeGpos_StructurePreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + var originalGpos = font.GposTable; + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + Assert.IsNotNull(reparsed.GposTable, "GPOS table should exist after roundtrip"); + Assert.AreEqual(originalGpos.MajorVersion, reparsed.GposTable.MajorVersion); + Assert.AreEqual(originalGpos.MinorVersion, reparsed.GposTable.MinorVersion); + + Assert.AreEqual( + originalGpos.ScriptList.ScriptRecords.Count, + reparsed.GposTable.ScriptList.ScriptRecords.Count, + "Script count should match"); + + Assert.AreEqual( + originalGpos.FeatureList.FeatureRecords.Count, + reparsed.GposTable.FeatureList.FeatureRecords.Count, + "Feature count should match"); + + Assert.AreEqual( + originalGpos.LookupList.Lookups.Count, + reparsed.GposTable.LookupList.Lookups.Count, + "Lookup count should match"); + + for (int i = 0; i < originalGpos.LookupList.Lookups.Count; i++) + { + Assert.AreEqual( + originalGpos.LookupList.Lookups[i].LookupType, + reparsed.GposTable.LookupList.Lookups[i].LookupType, + string.Format("Lookup[{0}] type should match", i)); + } + } + + [TestMethod] + public void SerializeGpos_FeatureTagsPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var originalTags = new List(); + foreach (var feature in font.GposTable.FeatureList.FeatureRecords) + originalTags.Add(feature.FeatureTag.Value); + originalTags.Sort(); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var reparsedTags = new List(); + foreach (var feature in reparsed.GposTable.FeatureList.FeatureRecords) + reparsedTags.Add(feature.FeatureTag.Value); + reparsedTags.Sort(); + + Assert.AreEqual(originalTags.Count, reparsedTags.Count, "Feature count should match"); + for (int i = 0; i < originalTags.Count; i++) + { + Assert.AreEqual(originalTags[i], reparsedTags[i], + string.Format("Feature tag[{0}] should match", i)); + } + + Debug.WriteLine(string.Format("Features preserved: {0}", string.Join(", ", reparsedTags.ToArray()))); + } + + [TestMethod] + public void SerializeGpos_ScriptTagsPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var originalTags = new List(); + foreach (var script in font.GposTable.ScriptList.ScriptRecords) + originalTags.Add(script.ScriptTag.Value); + originalTags.Sort(); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var reparsedTags = new List(); + foreach (var script in reparsed.GposTable.ScriptList.ScriptRecords) + reparsedTags.Add(script.ScriptTag.Value); + reparsedTags.Sort(); + + Assert.AreEqual(originalTags.Count, reparsedTags.Count, "Script count should match"); + for (int i = 0; i < originalTags.Count; i++) + { + Assert.AreEqual(originalTags[i], reparsedTags[i], + string.Format("Script tag[{0}] should match", i)); + } + + Debug.WriteLine(string.Format("Scripts preserved: {0}", string.Join(", ", reparsedTags.ToArray()))); + } + + #endregion + + #region PairPos (Type 2) Kerning Tests + + [TestMethod] + public void SerializeGpos_PairPos_KerningValuesPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var originalKerning = CollectKerningPairs(font); + Debug.WriteLine(string.Format("Original font has {0} kerning pairs", originalKerning.Count)); + Assert.IsTrue(originalKerning.Count > 0, "Font should have kerning pairs"); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var reparsedKerning = CollectKerningPairs(reparsed); + + Assert.AreEqual(originalKerning.Count, reparsedKerning.Count, "Kerning pair count should match"); + + int verified = 0; + foreach (var pair in originalKerning.Keys) + { + short expectedValue = originalKerning[pair]; + + Assert.IsTrue(reparsedKerning.ContainsKey(pair), + string.Format("Missing kerning pair ({0}, {1})", pair.FirstGlyph, pair.SecondGlyph)); + + short actualValue = reparsedKerning[pair]; + Assert.AreEqual(expectedValue, actualValue, + string.Format("Kerning value mismatch for ({0}, {1}): expected {2}, got {3}", + pair.FirstGlyph, pair.SecondGlyph, expectedValue, actualValue)); + + verified++; + } + + Debug.WriteLine(string.Format("Verified {0} kerning pairs", verified)); + } + + [TestMethod] + public void SerializeGpos_PairPos_SpecificPairsVerified() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + ushort fGlyph, eGlyph, aGlyph, vGlyph; + font.CmapTable.TryGetGlyphId('f', out fGlyph); + font.CmapTable.TryGetGlyphId('e', out eGlyph); + font.CmapTable.TryGetGlyphId('A', out aGlyph); + font.CmapTable.TryGetGlyphId('V', out vGlyph); + + var origLookup = FindFirstLookupOfType(font.GposTable, 2); + Assert.IsNotNull(origLookup, "Should have PairPos lookup"); + + var origSubtable = origLookup.SubTables[0] as PairPosSubTableFormat1; + Assert.IsNotNull(origSubtable, "Should have PairPos Format 1 subtable"); + + ValueRecord feOrig1, feOrig2, avOrig1, avOrig2; + bool hasFe = origSubtable.TryGetPairAdjustment(fGlyph, eGlyph, out feOrig1, out feOrig2); + bool hasAv = origSubtable.TryGetPairAdjustment(aGlyph, vGlyph, out avOrig1, out avOrig2); + + if (hasFe) Debug.WriteLine(string.Format("Original: f-e = {0}", feOrig1.XAdvance)); + if (hasAv) Debug.WriteLine(string.Format("Original: A-V = {0}", avOrig1.XAdvance)); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var newLookup = FindFirstLookupOfType(reparsed.GposTable, 2); + Assert.IsNotNull(newLookup, "Reparsed should have PairPos lookup"); + + var newSubtable = newLookup.SubTables[0] as PairPosSubTableFormat1; + Assert.IsNotNull(newSubtable, "Reparsed should have PairPos Format 1 subtable"); + + if (hasFe) + { + ValueRecord feNew1, feNew2; + Assert.IsTrue(newSubtable.TryGetPairAdjustment(fGlyph, eGlyph, out feNew1, out feNew2), "f-e pair should exist"); + Assert.AreEqual(feOrig1.XAdvance, feNew1.XAdvance, "f-e kerning should match"); + Debug.WriteLine(string.Format("f-e: {0} verified", feNew1.XAdvance)); + } + + if (hasAv) + { + ValueRecord avNew1, avNew2; + Assert.IsTrue(newSubtable.TryGetPairAdjustment(aGlyph, vGlyph, out avNew1, out avNew2), "A-V pair should exist"); + Assert.AreEqual(avOrig1.XAdvance, avNew1.XAdvance, "A-V kerning should match"); + Debug.WriteLine(string.Format("A-V: {0} verified", avNew1.XAdvance)); + } + } + + [TestMethod] + public void SerializeGpos_PairPos_ValueFormatPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var origLookup = FindFirstLookupOfType(font.GposTable, 2); + var origSubtable = origLookup.SubTables[0] as PairPosSubTableFormat1; + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var newLookup = FindFirstLookupOfType(reparsed.GposTable, 2); + var newSubtable = newLookup.SubTables[0] as PairPosSubTableFormat1; + + Assert.AreEqual(origSubtable.ValueFormat1, newSubtable.ValueFormat1, "ValueFormat1 should be preserved"); + Assert.AreEqual(origSubtable.ValueFormat2, newSubtable.ValueFormat2, "ValueFormat2 should be preserved"); + + Debug.WriteLine(string.Format("ValueFormat1: 0x{0:X4}", newSubtable.ValueFormat1)); + Debug.WriteLine(string.Format("ValueFormat2: 0x{0:X4}", newSubtable.ValueFormat2)); + } + + #endregion + + #region SinglePos (Type 1) Tests + + [TestMethod] + public void SerializeGpos_SinglePos_ValuesPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var singlePosLookup = FindFirstLookupOfType(font.GposTable, 1); + if (singlePosLookup == null) + { + Assert.Inconclusive("Roboto does not have SinglePos lookups"); + return; + } + + var originalAdjustments = CollectSinglePosAdjustments(font); + Debug.WriteLine(string.Format("Original has {0} single adjustments", originalAdjustments.Count)); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var reparsedAdjustments = CollectSinglePosAdjustments(reparsed); + + Assert.AreEqual(originalAdjustments.Count, reparsedAdjustments.Count, "SinglePos adjustment count should match"); + + foreach (ushort glyphId in originalAdjustments.Keys) + { + var expected = originalAdjustments[glyphId]; + + Assert.IsTrue(reparsedAdjustments.ContainsKey(glyphId), + string.Format("Missing adjustment for glyph {0}", glyphId)); + + var actual = reparsedAdjustments[glyphId]; + + Assert.AreEqual(expected.XPlacement, actual.XPlacement, string.Format("Glyph {0} XPlacement", glyphId)); + Assert.AreEqual(expected.YPlacement, actual.YPlacement, string.Format("Glyph {0} YPlacement", glyphId)); + Assert.AreEqual(expected.XAdvance, actual.XAdvance, string.Format("Glyph {0} XAdvance", glyphId)); + Assert.AreEqual(expected.YAdvance, actual.YAdvance, string.Format("Glyph {0} YAdvance", glyphId)); + } + + Debug.WriteLine(string.Format("Verified {0} single adjustments", originalAdjustments.Count)); + } + + #endregion + + #region MarkToBase (Type 4) Tests + + [TestMethod] + public void SerializeGpos_MarkToBase_StructurePreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var markToBaseLookup = FindFirstLookupOfType(font.GposTable, 4); + if (markToBaseLookup == null) + { + Assert.Inconclusive("Roboto does not have MarkToBase lookups"); + return; + } + + var origSubtable = markToBaseLookup.SubTables[0] as MarkToBaseSubTableFormat1; + Assert.IsNotNull(origSubtable, "Should have MarkToBase subtable"); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var newLookup = FindFirstLookupOfType(reparsed.GposTable, 4); + Assert.IsNotNull(newLookup, "MarkToBase lookup should exist"); + + var newSubtable = newLookup.SubTables[0] as MarkToBaseSubTableFormat1; + Assert.IsNotNull(newSubtable, "MarkToBase subtable should exist"); + + Assert.AreEqual(origSubtable.MarkClassCount, newSubtable.MarkClassCount, "MarkClassCount"); + Assert.AreEqual(origSubtable.MarkArray.MarkCount, newSubtable.MarkArray.MarkCount, "MarkCount"); + Assert.AreEqual(origSubtable.BaseArray.BaseCount, newSubtable.BaseArray.BaseCount, "BaseCount"); + + Debug.WriteLine(string.Format("MarkToBase preserved: {0} classes, {1} marks, {2} bases", + newSubtable.MarkClassCount, newSubtable.MarkArray.MarkCount, newSubtable.BaseArray.BaseCount)); + } + + [TestMethod] + public void SerializeGpos_MarkToBase_AnchorPointsPreserved() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var markToBaseLookup = FindFirstLookupOfType(font.GposTable, 4); + if (markToBaseLookup == null) + { + Assert.Inconclusive("Roboto does not have MarkToBase lookups"); + return; + } + + var origSubtable = markToBaseLookup.SubTables[0] as MarkToBaseSubTableFormat1; + var originalAttachments = CollectMarkToBaseAttachments(origSubtable); + + if (originalAttachments.Count == 0) + { + Assert.Inconclusive("No attachments found"); + return; + } + + Debug.WriteLine(string.Format("Found {0} mark-base attachments", originalAttachments.Count)); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + var newLookup = FindFirstLookupOfType(reparsed.GposTable, 4); + var newSubtable = newLookup.SubTables[0] as MarkToBaseSubTableFormat1; + + int verified = 0; + int maxToVerify = 50; + + foreach (var pair in originalAttachments.Keys) + { + if (verified >= maxToVerify) break; + + var expected = originalAttachments[pair]; + + AnchorTable newMarkAnchor, newBaseAnchor; + Assert.IsTrue(newSubtable.TryGetAttachment(pair.FirstGlyph, pair.SecondGlyph, out newMarkAnchor, out newBaseAnchor), + string.Format("Missing attachment for mark {0}, base {1}", pair.FirstGlyph, pair.SecondGlyph)); + + Assert.AreEqual(expected.MarkAnchorX, newMarkAnchor.XCoordinate, + string.Format("Mark anchor X for ({0}, {1})", pair.FirstGlyph, pair.SecondGlyph)); + Assert.AreEqual(expected.MarkAnchorY, newMarkAnchor.YCoordinate, + string.Format("Mark anchor Y for ({0}, {1})", pair.FirstGlyph, pair.SecondGlyph)); + Assert.AreEqual(expected.BaseAnchorX, newBaseAnchor.XCoordinate, + string.Format("Base anchor X for ({0}, {1})", pair.FirstGlyph, pair.SecondGlyph)); + Assert.AreEqual(expected.BaseAnchorY, newBaseAnchor.YCoordinate, + string.Format("Base anchor Y for ({0}, {1})", pair.FirstGlyph, pair.SecondGlyph)); + + verified++; + } + + Debug.WriteLine(string.Format("Verified {0} anchor point pairs", verified)); + } + + #endregion + + #region Feature-Lookup Index Integrity Tests + + [TestMethod] + public void SerializeGpos_FeatureLookupIndices_AreValid() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + int lookupCount = reparsed.GposTable.LookupList.Lookups.Count; + + foreach (var feature in reparsed.GposTable.FeatureList.FeatureRecords) + { + foreach (var idx in feature.FeatureTable.LookupListIndices) + { + Assert.IsTrue(idx < lookupCount, + string.Format("Feature '{0}' references invalid lookup index {1} (max={2})", + feature.FeatureTag.Value, idx, lookupCount - 1)); + } + } + + Debug.WriteLine(string.Format("All feature->lookup indices valid (max index: {0})", lookupCount - 1)); + } + + [TestMethod] + public void Diagnose_GposTableOffset() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + Debug.WriteLine("=== TABLE RECORDS ==="); + foreach (var kvp in font.TableRecords) + { + Debug.WriteLine(string.Format("{0}: Offset={1}, Length={2}", + kvp.Key, kvp.Value.Offset, kvp.Value.Length)); + } + + Debug.WriteLine(string.Format("\n=== READER STATE ===")); + Debug.WriteLine(string.Format("Reader stream length: {0}", font._tblSettings.TableReaderFactory.FontBytesLength)); + + Debug.WriteLine("\n=== LOADING GPOS ==="); + var gpos = font.GposTable; + Debug.WriteLine(string.Format("GPOS version: {0}.{1}", gpos.MajorVersion, gpos.MinorVersion)); + } + + [TestMethod] + public void SerializeGpos_LangSysFeatureIndices_AreValid() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + int featureCount = reparsed.GposTable.FeatureList.FeatureRecords.Count; + + foreach (var script in reparsed.GposTable.ScriptList.ScriptRecords) + { + if (script.ScriptTable.DefaultLangSys != null) + { + foreach (var idx in script.ScriptTable.DefaultLangSys.FeatureIndices) + { + Assert.IsTrue(idx < featureCount, + string.Format("Script '{0}' DefaultLangSys references invalid feature index {1}", + script.ScriptTag.Value, idx)); + } + } + + foreach (var langSys in script.ScriptTable.LangSysRecords) + { + foreach (var idx in langSys.LangSysTable.FeatureIndices) + { + Assert.IsTrue(idx < featureCount, + string.Format("Script '{0}' LangSys '{1}' references invalid feature index {2}", + script.ScriptTag.Value, langSys.LangSysTag, idx)); + } + } + } + + Debug.WriteLine(string.Format("All LangSys->feature indices valid (max index: {0})", featureCount - 1)); + } + + #endregion + + #region Coverage Table Integrity Tests + + [TestMethod] + public void SerializeGpos_CoverageGlyphIds_AreValid() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + var serializer = new OpenTypeFontSerializer(font); + var bytes = serializer.Serialize(); + var reparsed = new OpenTypeFont(bytes); + + ushort maxGlyph = reparsed.MaxpTable.numGlyphs; + + for (int lookupIdx = 0; lookupIdx < reparsed.GposTable.LookupList.Lookups.Count; lookupIdx++) + { + var lookup = reparsed.GposTable.LookupList.Lookups[lookupIdx]; + + for (int subtableIdx = 0; subtableIdx < lookup.SubTables.Count; subtableIdx++) + { + var subtable = lookup.SubTables[subtableIdx]; + var coverages = GetCoveragesFromSubtable(subtable); + + foreach (var coverage in coverages) + { + var glyphIds = coverage.GetCoveredGlyphs(); + foreach (var glyphId in glyphIds) + { + Assert.IsTrue(glyphId < maxGlyph, + string.Format("Lookup type {0} subtable {1}: Coverage references invalid glyph {2} (max={3})", + lookup.LookupType, subtableIdx, glyphId, maxGlyph - 1)); + } + } + } + } + + Debug.WriteLine(string.Format("All coverage glyph IDs valid (max glyph: {0})", maxGlyph - 1)); + } + + #endregion + + #region Helper Methods + + private LookupTable FindFirstLookupOfType(GposTable gpos, int lookupType) + { + if (gpos == null) return null; + + foreach (var lookup in gpos.LookupList.Lookups) + { + if (lookup.LookupType == lookupType) + return lookup; + } + return null; + } + + private Dictionary CollectKerningPairs(OpenTypeFont font) + { + var result = new Dictionary(); + + var pairPosLookup = FindFirstLookupOfType(font.GposTable, 2); + if (pairPosLookup == null) return result; + + foreach (var subtableObj in pairPosLookup.SubTables) + { + var subtable = subtableObj as PairPosSubTableFormat1; + if (subtable == null) continue; + + var coveredGlyphs = subtable.Coverage.GetCoveredGlyphs(); + + for (int i = 0; i < coveredGlyphs.Length && i < subtable.PairSets.Count; i++) + { + ushort firstGlyph = coveredGlyphs[i]; + var pairSet = subtable.PairSets[i]; + + if (pairSet == null) continue; + + foreach (var pair in pairSet.PairValueRecords) + { + var key = new GlyphPair(firstGlyph, pair.SecondGlyph); + result[key] = pair.Value1.XAdvance; + } + } + } + + return result; + } + + private Dictionary CollectSinglePosAdjustments(OpenTypeFont font) + { + var result = new Dictionary(); + + var singlePosLookup = FindFirstLookupOfType(font.GposTable, 1); + if (singlePosLookup == null) return result; + + foreach (var subtableObj in singlePosLookup.SubTables) + { + var f1 = subtableObj as SinglePosSubTableFormat1; + if (f1 != null) + { + var glyphIds = f1.Coverage.GetCoveredGlyphs(); + foreach (var glyphId in glyphIds) + { + result[glyphId] = new SinglePosValue + { + XPlacement = f1.Value.XPlacement, + YPlacement = f1.Value.YPlacement, + XAdvance = f1.Value.XAdvance, + YAdvance = f1.Value.YAdvance + }; + } + continue; + } + + var f2 = subtableObj as SinglePosSubTableFormat2; + if (f2 != null) + { + var glyphIds = f2.Coverage.GetCoveredGlyphs(); + for (int i = 0; i < glyphIds.Length && i < f2.Values.Length; i++) + { + result[glyphIds[i]] = new SinglePosValue + { + XPlacement = f2.Values[i].XPlacement, + YPlacement = f2.Values[i].YPlacement, + XAdvance = f2.Values[i].XAdvance, + YAdvance = f2.Values[i].YAdvance + }; + } + } + } + + return result; + } + + private Dictionary CollectMarkToBaseAttachments( + MarkToBaseSubTableFormat1 subtable) + { + var result = new Dictionary(); + + var markGlyphs = subtable.MarkCoverage.GetCoveredGlyphs(); + var baseGlyphs = subtable.BaseCoverage.GetCoveredGlyphs(); + + int markLimit = markGlyphs.Length > 100 ? 100 : markGlyphs.Length; + int baseLimit = baseGlyphs.Length > 100 ? 100 : baseGlyphs.Length; + + for (int m = 0; m < markLimit; m++) + { + ushort markGlyph = markGlyphs[m]; + + for (int b = 0; b < baseLimit; b++) + { + ushort baseGlyph = baseGlyphs[b]; + + AnchorTable markAnchor, baseAnchor; + if (subtable.TryGetAttachment(markGlyph, baseGlyph, out markAnchor, out baseAnchor)) + { + var key = new GlyphPair(markGlyph, baseGlyph); + result[key] = new AnchorPointPair + { + MarkAnchorX = markAnchor.XCoordinate, + MarkAnchorY = markAnchor.YCoordinate, + BaseAnchorX = baseAnchor.XCoordinate, + BaseAnchorY = baseAnchor.YCoordinate + }; + } + } + } + + return result; + } + + private List GetCoveragesFromSubtable(object subtable) + { + var coverages = new List(); + + var pp1 = subtable as PairPosSubTableFormat1; + if (pp1 != null) { coverages.Add(pp1.Coverage); return coverages; } + + var sp1 = subtable as SinglePosSubTableFormat1; + if (sp1 != null) { coverages.Add(sp1.Coverage); return coverages; } + + var sp2 = subtable as SinglePosSubTableFormat2; + if (sp2 != null) { coverages.Add(sp2.Coverage); return coverages; } + + var mtb = subtable as MarkToBaseSubTableFormat1; + if (mtb != null) { coverages.Add(mtb.MarkCoverage); coverages.Add(mtb.BaseCoverage); return coverages; } + + return coverages; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Serialization/GlyphTableSerializationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Serialization/GlyphTableSerializationTests.cs new file mode 100644 index 0000000000..d714ae0861 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Serialization/GlyphTableSerializationTests.cs @@ -0,0 +1,62 @@ +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Tests.Serialization +{ + [TestClass] + public class GlyphTableSerializationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void SerializeLocaTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("loca"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var locaBytes = font.LocaTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, locaBytes?.Length); + CollectionAssert.AreEqual(originalBytes, locaBytes); + } + + [TestMethod] + public void SerializeHtmxTable() + { + var ffi = FontScannerV2.FindBestMatch(FontFolder, "Roboto", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("hmtx"); + + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var hmtxBytes = font?.HmtxTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, hmtxBytes?.Length); + CollectionAssert.AreEqual(originalBytes, hmtxBytes); + } + + [TestMethod] + [DataRow("Roboto", FontSubFamily.Regular)] + [DataRow("Noto Emoji", FontSubFamily.Regular)] + [DataRow("EB Garamond", FontSubFamily.Regular)] + [DataRow("Mulish", FontSubFamily.Regular)] + public void SerializeGlyfTable(string fontName, FontSubFamily subFamily) + { + var ffi = FontScannerV2.FindBestMatch(FontFolders, fontName, subFamily); + var originalBytes = ffi.GetTableBytes("glyf"); + + var font = TestFolderEngine.LoadFont(fontName, subFamily); + var glyfBytes = font.GlyfTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, glyfBytes?.Length, + $"Font {fontName} {subFamily} Length differ"); + CollectionAssert.AreEqual(originalBytes, glyfBytes, + $"Font {fontName} {subFamily} Bytes differ"); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Serialization/KernSerializationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Serialization/KernSerializationTests.cs new file mode 100644 index 0000000000..517675118a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Serialization/KernSerializationTests.cs @@ -0,0 +1,45 @@ +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Serialization +{ + [TestClass] + public class KernSerializationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + [Ignore("Was only able to find fonts with kern table among Windows fonts. These cannot be distributed with the test project due to licensing.")] + public void SerializeKernTable() + { + var ffi = FontScannerV2.FindBestMatch(@"c:\windows\fonts", "Arial", FontSubFamily.Regular); + var originalBytes = ffi.GetTableBytes("kern"); + + var font = OpenTypeFonts.LoadFont("Arial"); + var kernBytes = font?.KernTable.Serialize(font); + + Assert.AreEqual(originalBytes.Length, kernBytes?.Length); + CollectionAssert.AreEqual(originalBytes, kernBytes); + } + + [TestMethod, Ignore] + public void FindKernTable() + { + var fonts = FontScannerV2.GetAllScannedFontsInPath(@"c:\windows\fonts"); + var kernFonts = new List(); + foreach (var font in fonts) + { + if (font.TableRecords.ContainsKey("kern") || font.TableRecords.ContainsKey("Kern")) + { + kernFonts.Add(font); + } + } + var c = kernFonts.Count; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Subsetting/BasicSubsettingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/BasicSubsettingTests.cs new file mode 100644 index 0000000000..c75f92cad8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/BasicSubsettingTests.cs @@ -0,0 +1,491 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Basic subsetting tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using System.Diagnostics; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tests.Subsetting +{ + [TestClass] + public class BasicSubsettingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void Subset_Abc_RoundtripValidation() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subsetFont = font.CreateSubset(new[] { 'a', 'b', 'c' }); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + Assert.AreEqual(12, parsedFont.TableRecords.Count); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("head")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("name")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("maxp")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("hhea")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("hmtx")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("loca")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("glyf")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("cmap")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("post")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("OS/2")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("GSUB")); + Assert.IsTrue(parsedFont.TableRecords.ContainsKey("GPOS")); + + FontTestHelper.AssertFontValid(parsedFont); + + int ligatureCount = FontTestHelper.CountLigatures(parsedFont); + Assert.AreEqual(0, ligatureCount, "abc should have NO ligatures"); + + int expectedGlyphs = 3; // a, b, c + expectedGlyphs += 1; // + space (U+0020) + expectedGlyphs += 1; // + .notdef (GID 0) + expectedGlyphs += 5; // + variants from Single Substitution + + Assert.AreEqual((ushort)expectedGlyphs, parsedFont.MaxpTable.numGlyphs); + Assert.AreEqual((ushort)expectedGlyphs, parsedFont.HheaTable.numberOfHMetrics); + + Assert.IsTrue(parsedFont.CmapTable.ContainsChar(32)); + } + + [TestMethod] + public void Subset_Fiffig_WithFullValidation() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subsetFont = font.CreateSubset("fiffig"); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + } + + [TestMethod] + public void Subset_SingleChar_ShouldWork() + { + var font = TestFolderEngine.LoadFont("Mulish"); + var subsetFont = font.CreateSubset(new[] { 'a' }); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + } + + [TestMethod] + public void Subset_MultipleChars_ShouldWork() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subsetFont = font.CreateSubset(new[] { + 'F', 'l', 'y', 'g', 'a', 'n', 'd', 'e', 'b', 'ä', 'c', 'k', 's', 'i', 'r', 'ö', 'h', 'w', 'p', 'å', + 'm', 'j', 'u', 't', 'v', 'o', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' + }); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + } + + [TestMethod] + public void Subset_RoundtripHelper_ShouldWork() + { + var parsedFont = FontTestHelper.RoundtripSubset("Roboto", "test", FontFolders); + + SaveFontForCurrentTest(parsedFont); + + Assert.IsNotNull(parsedFont); + Assert.IsTrue(parsedFont.MaxpTable.numGlyphs > 0); + } + + [TestMethod] + public void Check_Original_Roboto_Ligatures() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + font.CmapTable.TryGetGlyphId('f', out ushort fGlyph); + font.CmapTable.TryGetGlyphId('i', out ushort iGlyph); + font.CmapTable.TryGetGlyphId('o', out ushort oGlyph); + font.CmapTable.TryGetGlyphId('g', out ushort gGlyph); + + Debug.WriteLine("=== ORIGINAL ROBOTO ==="); + Debug.WriteLine($"'f' = glyph {fGlyph}"); + Debug.WriteLine($"'i' = glyph {iGlyph}"); + Debug.WriteLine($"'o' = glyph {oGlyph}"); + Debug.WriteLine($"'g' = glyph {gGlyph}"); + + Debug.WriteLine("\n=== ORIGINAL LIGATURES ==="); + var ligLookups = font.GsubTable.LookupList.Lookups.Where(l => l.LookupType == 4).ToList(); + + foreach (var lookup in ligLookups) + { + foreach (var subtable in lookup.SubTables) + { + var ligSubtable = subtable as LigatureSubstSubTable; + if (ligSubtable != null && ligSubtable.LigatureSets.ContainsKey(fGlyph)) + { + var ligSet = ligSubtable.LigatureSets[fGlyph]; + Debug.WriteLine($"First glyph {fGlyph} ('f') has {ligSet.Ligatures.Count} ligatures:"); + + foreach (var lig in ligSet.Ligatures) + { + var componentIds = string.Join(", ", lig.Components.Select(c => c.ToString()).ToArray()); + Debug.WriteLine($" Output: {lig.LigatureGlyph}, Components: [{componentIds}]"); + } + } + } + } + } + + [TestMethod] + public void Subset_Ligatures_ShouldStillWork() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + + Debug.WriteLine("=== ORIGINAL ROBOTO ==="); + if (font.GsubTable != null) + { + var origLigLookups = font.GsubTable.LookupList.Lookups.Where(l => l.LookupType == 4).ToList(); + Debug.WriteLine($"Original has {origLigLookups.Count} ligature lookups"); + + font.CmapTable.TryGetGlyphId('f', out ushort origF); + Debug.WriteLine($"'f' = glyph {origF} in original"); + + foreach (var lookup in origLigLookups) + { + foreach (var subtable in lookup.SubTables) + { + var ligSubtable = subtable as LigatureSubstSubTable; + if (ligSubtable != null && ligSubtable.LigatureSets.ContainsKey(origF)) + { + var ligSet = ligSubtable.LigatureSets[origF]; + Debug.WriteLine($" 'f' has {ligSet.Ligatures.Count} ligatures in original"); + } + } + } + } + + Debug.WriteLine("\n=== ORIGINAL FEATURES ==="); + for (int i = 0; i < font.GsubTable.FeatureList.FeatureRecords.Count && i < 10; i++) + { + var feat = font.GsubTable.FeatureList.FeatureRecords[i]; + Debug.WriteLine($"Feature[{i}]: '{feat.FeatureTag.Value}'"); + } + + Debug.WriteLine("\n=== CREATING SUBSET ==="); + var subsetFont = font.CreateSubset("fiffigoffice"); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + Debug.WriteLine("\n=== SUBSET FONT ==="); + Debug.WriteLine($"Total glyphs: {parsedFont.MaxpTable.numGlyphs}"); + + parsedFont.CmapTable.TryGetGlyphId('f', out ushort subsetF); + parsedFont.CmapTable.TryGetGlyphId('i', out ushort subsetI); + Debug.WriteLine($"'f' = glyph {subsetF}"); + Debug.WriteLine($"'i' = glyph {subsetI}"); + + Assert.IsNotNull(parsedFont.GsubTable, "GSUB should be present"); + + Debug.WriteLine($"\n=== GSUB FEATURES (DETAILED) ==="); + foreach (var feature in parsedFont.GsubTable.FeatureList.FeatureRecords) + { + int lookupCount = feature.FeatureTable?.LookupListIndices?.Length ?? 0; + Debug.WriteLine($"Feature: '{feature.FeatureTag.Value}', Lookups: {lookupCount}"); + } + + var ligLookups = parsedFont.GsubTable.LookupList.Lookups + .Where(l => l.LookupType == 4) + .ToList(); + + Debug.WriteLine($"\n=== LIGATURE LOOKUPS ==="); + Debug.WriteLine($"Found {ligLookups.Count} ligature lookups"); + + Assert.IsTrue(ligLookups.Count > 0, "Should have ligature lookups"); + + foreach (var lookup in ligLookups) + { + foreach (var subtable in lookup.SubTables) + { + var ligSubtable = subtable as LigatureSubstSubTable; + if (ligSubtable != null) + { + Debug.WriteLine($"\nLigature subtable has {ligSubtable.LigatureSets.Count} sets"); + + if (ligSubtable.LigatureSets.ContainsKey(subsetF)) + { + var ligSet = ligSubtable.LigatureSets[subsetF]; + Debug.WriteLine($"'f' (glyph {subsetF}) has {ligSet.Ligatures.Count} ligatures:"); + + foreach (var lig in ligSet.Ligatures) + { + var componentIds = string.Join(", ", lig.Components.Select(c => c.ToString()).ToArray()); + Debug.WriteLine($" Output: {lig.LigatureGlyph}, Components: [{componentIds}]"); + } + } + else + { + Debug.WriteLine($"'f' (glyph {subsetF}) NOT FOUND in LigatureSets!"); + Debug.WriteLine($"Available first glyphs: {string.Join(", ", ligSubtable.LigatureSets.Keys.Select(k => k.ToString()).ToArray())}"); + } + } + } + } + + Debug.WriteLine($"\n=== SCRIPTLIST & LANGSYS ==="); + if (parsedFont.GsubTable.ScriptList != null) + { + foreach (var scriptRecord in parsedFont.GsubTable.ScriptList.ScriptRecords) + { + string scriptTag = scriptRecord.ScriptTag.Value; + Debug.WriteLine($"\nScript: '{scriptTag}'"); + + var scriptTable = scriptRecord.ScriptTable; + + if (scriptTable.DefaultLangSys != null) + { + var defLang = scriptTable.DefaultLangSys; + Debug.WriteLine($" DefaultLangSys:"); + Debug.WriteLine($" RequiredFeatureIndex: {defLang.RequiredFeatureIndex}"); + Debug.WriteLine($" FeatureIndices: [{string.Join(", ", defLang.FeatureIndices.Select(i => i.ToString()).ToArray())}]"); + + foreach (var featIdx in defLang.FeatureIndices) + { + if (featIdx < parsedFont.GsubTable.FeatureList.FeatureRecords.Count) + { + var feat = parsedFont.GsubTable.FeatureList.FeatureRecords[featIdx]; + Debug.WriteLine($" Feature[{featIdx}]: '{feat.FeatureTag.Value}'"); + } + } + } + } + } + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + } + + [TestMethod] + public void Subset_WithGposKerning_ShouldPreservePositioning() + { + var font = TestFolderEngine.LoadFont("Roboto Extra Light"); + //var font = OpenTypeFonts.LoadFont("Roboto Extra Light"); + var chars = new[] { 'f', 'e', 'c', 'd', 'g', 'E', 'a', 'b', ' ' }; + + bool foundF_Original = font.CmapTable.TryGetGlyphId('f', out ushort fGlyphOrig); + bool foundE_Original = font.CmapTable.TryGetGlyphId('e', out ushort eGlyphOrig); + + Debug.WriteLine($"=== ORIGINAL FONT ==="); + Debug.WriteLine($"f = glyph {fGlyphOrig}"); + Debug.WriteLine($"e = glyph {eGlyphOrig}"); + + Assert.IsTrue(foundF_Original && foundE_Original, "Should find f and e in original"); + + bool hasOriginalKerning = false; + if (font.GposTable != null) + { + var kernLookupsOrig = font.GposTable.LookupList.Lookups.Where(l => l.LookupType == 2).ToList(); + foreach (var lookup in kernLookupsOrig) + { + var subtable = lookup.SubTables.FirstOrDefault() as PairPosSubTableFormat1; + if (subtable != null && subtable.TryGetPairAdjustment(fGlyphOrig, eGlyphOrig, out var val1, out var val2)) + { + Debug.WriteLine($"ORIGINAL: f-e kerning = {val1.XAdvance}"); + hasOriginalKerning = true; + break; + } + } + } + + Assert.IsTrue(hasOriginalKerning, "f-e should have kerning in original font"); + + Debug.WriteLine($"\n=== CREATING SUBSET ==="); + var subsetFont = font.CreateSubset(chars); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + bool foundF = parsedFont.CmapTable.TryGetGlyphId('f', out ushort fGlyph); + bool foundE = parsedFont.CmapTable.TryGetGlyphId('e', out ushort eGlyph); + + Debug.WriteLine($"\n=== SUBSET FONT ==="); + Debug.WriteLine($"f = glyph {fGlyph}"); + Debug.WriteLine($"e = glyph {eGlyph}"); + + Assert.IsNotNull(parsedFont.GposTable, "GPOS table should be present in subset"); + + var kernLookups = parsedFont.GposTable.LookupList.Lookups.Where(l => l.LookupType == 2).ToList(); + Assert.IsTrue(kernLookups.Count > 0, "Should have at least one kerning lookup"); + + bool hasKerning = false; + foreach (var lookup in kernLookups) + { + var subtable = lookup.SubTables.FirstOrDefault() as PairPosSubTableFormat1; + if (subtable != null) + { + if (subtable.TryGetPairAdjustment(fGlyph, eGlyph, out var val1, out var val2)) + { + Debug.WriteLine($"SUBSET: f-e kerning = {val1.XAdvance}"); + hasKerning = true; + Assert.AreEqual(-24, val1.XAdvance, "Kerning value should match original"); + break; + } + } + } + + Assert.IsTrue(hasKerning, "f-e kerning pair should be preserved in subset"); + } + + [TestMethod] + public void Subset_WithGposSingleAdjustment_ShouldPreserve() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + var chars = new[] { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'A', 'B', 'C', 'D', 'E', ' ' + }; + + var subsetFont = font.CreateSubset(chars); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + + if (parsedFont.GposTable != null) + { + var singlePosLookups = parsedFont.GposTable.LookupList.Lookups + .Where(l => l.LookupType == 1) + .ToList(); + + if (singlePosLookups.Count > 0) + System.Diagnostics.Debug.WriteLine($"✅ Subset has {singlePosLookups.Count} SinglePos lookup(s)"); + else + System.Diagnostics.Debug.WriteLine("ℹ️ No SinglePos lookups in subset (may not be present in Roboto)"); + } + } + + [TestMethod] + public void Subset_WithGposMarkToBase_ShouldPreserveAccents() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + var chars = new[] { + 'e', 'a', 'o', 'u', 'i', 'n', + 'é', 'à', 'ö', 'ü', 'ñ', ' ', + 'E', 'A', 'O', 'U' + }; + + var subsetFont = font.CreateSubset(chars); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + + if (parsedFont.GposTable != null) + { + var markToBaseLookups = parsedFont.GposTable.LookupList.Lookups + .Where(l => l.LookupType == 4) + .ToList(); + + if (markToBaseLookups.Count > 0) + { + System.Diagnostics.Debug.WriteLine($"✅ Subset has {markToBaseLookups.Count} MarkToBase lookup(s)"); + + var subtable = markToBaseLookups[0].SubTables.FirstOrDefault() as MarkToBaseSubTableFormat1; + if (subtable != null) + { + System.Diagnostics.Debug.WriteLine($" MarkClassCount: {subtable.MarkClassCount}"); + System.Diagnostics.Debug.WriteLine($" Marks: {subtable.MarkArray?.MarkCount ?? 0}"); + System.Diagnostics.Debug.WriteLine($" Bases: {subtable.BaseArray?.BaseCount ?? 0}"); + } + } + else + { + System.Diagnostics.Debug.WriteLine("ℹ️ No MarkToBase lookups in subset (may not be present in Roboto)"); + } + } + } + + [TestMethod] + public void Subset_CompleteGposTest_AllThreeLookupTypes() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var text = "AVTO Wave Typography TEST café résumé ñoño 123"; + var subsetFont = font.CreateSubset(text); + + var serializer = new OpenTypeFontSerializer(subsetFont); + var bytes = serializer.Serialize(); + var parsedFont = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsedFont); + + FontTestHelper.AssertFontValid(parsedFont, FontValidationSeverity.Warning); + + if (parsedFont.GposTable != null) + { + System.Diagnostics.Debug.WriteLine("=== GPOS Subsetting Results ==="); + System.Diagnostics.Debug.WriteLine($"Total lookups: {parsedFont.GposTable.LookupList.Lookups.Count}"); + + var lookupsByType = parsedFont.GposTable.LookupList.Lookups + .GroupBy(l => l.LookupType) + .ToDictionary(g => g.Key, g => g.Count()); + + foreach (var kvp in lookupsByType) + { + string typeName = kvp.Key switch + { + 1 => "SinglePos", + 2 => "PairPos (Kerning)", + 4 => "MarkToBase", + _ => $"Type {kvp.Key}" + }; + System.Diagnostics.Debug.WriteLine($" {typeName}: {kvp.Value} lookup(s)"); + } + + Assert.IsTrue(parsedFont.GposTable.LookupList.Lookups.Count > 0, + "Should have at least some GPOS lookups preserved"); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Subsetting/CompositeGlyphSubsettingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/CompositeGlyphSubsettingTests.cs new file mode 100644 index 0000000000..830bcc550a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/CompositeGlyphSubsettingTests.cs @@ -0,0 +1,81 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Composite glyph subsetting tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.Subsetting +{ + [TestClass] + public class CompositeGlyphSubsettingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void Subset_Roboto_With_ÅÄÖ_Should_Work() + { + var font = TestFolderEngine.LoadFont("Roboto"); + + // Get the original å + var ågId = font.CmapTable.MapCharToGlyph('å'); + var åglyph = font.GlyfTable.GetGlyph((ushort)ågId); + + var subset = font.CreateSubset("Testar åäö ÅÄÖ och även é û č ć đ ł".Distinct()); + + // Save for inspection (CI/CD safe) + SaveFont("Roboto-subset-aao.ttf", subset); + + // Verify that 'å' actually has a composite glyph + var åGlyphId = subset.CmapTable.MapCharToGlyph('å'); + var glyph = subset.GlyfTable.GetGlyph((ushort)åGlyphId); + + Assert.IsTrue(glyph.Header.numberOfContours < 0, "å should be composite"); + Assert.IsTrue(glyph.CompositeData.Components.Count > 0); + } + + [TestMethod] + public void Subset_Mulish_With_ÅÄÖ_Should_Work() + { + var font = TestFolderEngine.LoadFont("Mulish", FontSubFamily.Regular); + var subset = font.CreateSubset("Testar åäö ÅÄÖ och även é û č ć đ ł".Distinct()); + + // Save for inspection (CI/CD safe) + SaveFont("Mulish-subset-aao.ttf", subset); + + // Verify that 'å' actually has a composite glyph + var åGlyphId = subset.CmapTable.MapCharToGlyph('å'); + var glyph = subset.GlyfTable.GetGlyph((ushort)åGlyphId); + + Assert.IsTrue(glyph.Header.numberOfContours < 0, "å should be composite"); + Assert.IsTrue(glyph.CompositeData.Components.Count > 0); + } + + [TestMethod] + public void Subset_BIZUDGothic_With_ÅÄÖ_Should_Work() + { + var font = TestFolderEngine.LoadFont("BIZUDGothic", FontSubFamily.Regular); + var subset = font.CreateSubset("Testar åäö ÅÄÖ och även é û č ć đ ł".Distinct()); + + // Save for inspection (CI/CD safe) + SaveFont("BIZUDGothic-subset-aao.ttf", subset); + + // Verify that 'å' is a simple glyph in BIZUDGothic (not composite) + var åGlyphId = subset.CmapTable.MapCharToGlyph('å'); + var glyph = subset.GlyfTable.GetGlyph((ushort)åGlyphId); + + Assert.AreEqual(4, glyph.Header.numberOfContours, "BIZUDGothic å should be simple with 4 contours"); + Assert.IsNotNull(glyph.SimpleData); + Assert.IsNull(glyph.CompositeData); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Subsetting/LigatureSubsettingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/LigatureSubsettingTests.cs new file mode 100644 index 0000000000..52e4998124 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/LigatureSubsettingTests.cs @@ -0,0 +1,127 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Ligature subsetting tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tests.Helpers; + +namespace EPPlus.Fonts.OpenType.Tests.Subsetting +{ + /// + /// Tests for GSUB ligature subsetting functionality + /// + [TestClass] + public class LigatureSubsettingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void Subset_Abc_ShouldHaveNoLigatures() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset(new[] { 'a', 'b', 'c' }); + + SaveFontForCurrentTest(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.AreEqual(0, ligCount, "abc should have NO ligatures"); + } + + [TestMethod] + public void Subset_Fiffig_ShouldHaveThreeLigatures() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("fiffig"); + + SaveFontForCurrentTest(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.AreEqual(3, ligCount, "fiffig should have fi, ff, ffi ligatures"); + } + + [TestMethod] + public void Subset_Fi_ShouldHaveFiLigature() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("fi"); + + SaveFontForCurrentTest(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.IsTrue(ligCount >= 1, "fi should have at least fi ligature"); + } + + [TestMethod] + public void Subset_Ff_ShouldHaveFfLigature() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("ff"); + + SaveFontForCurrentTest(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.IsTrue(ligCount >= 1, "ff should have ff ligature"); + } + + [TestMethod] + [DataRow("fi")] + [DataRow("ffi")] + [DataRow("ff")] + [DataRow("fl")] + public void Subset_CommonLigatures_ShouldWork(string text) + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset(text); + + SaveFontForCurrentTest(subset, text); + + Assert.IsNotNull(subset); + FontTestHelper.AssertFontValid(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.IsTrue(ligCount > 0, $"{text} should have ligatures"); + } + + [TestMethod] + public void Subset_OnlyF_ShouldNotCrash() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("f"); + + SaveFontForCurrentTest(subset); + + Assert.IsNotNull(subset); + Assert.IsTrue(subset.MaxpTable.numGlyphs > 0); + FontTestHelper.AssertFontValid(subset); + } + + [TestMethod] + public void Subset_Office_ShouldHaveFfiLigature() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("office"); + + SaveFontForCurrentTest(subset); + + int ligCount = FontTestHelper.CountLigatures(subset); + Assert.IsTrue(ligCount >= 1, "office should trigger ffi ligature"); + } + + [TestMethod] + public void Subset_HasLigatureLookupType() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("fi"); + + bool hasLigatures = FontTestHelper.HasGsubLookupType(subset, 4); + Assert.IsTrue(hasLigatures, "Should have ligature lookup (Type 4)"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Subsetting/SubsettingEdgeCasesTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/SubsettingEdgeCasesTests.cs new file mode 100644 index 0000000000..9808c7586e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/SubsettingEdgeCasesTests.cs @@ -0,0 +1,132 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/22/2025 EPPlus Software AB Subsetting edge case tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using EPPlus.Fonts.OpenType.TextShaping; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.Subsetting +{ + [TestClass] + public class SubsettingEdgeCasesTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void Subset_EmptyString_ShouldThrow() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void Subset_NullArray_ShouldThrow() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset((char[])null); + } + + [TestMethod] + public void Subset_SingleChar_ShouldHaveMinimalGlyphs() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("a"); + + SaveFont("edge_single_char.ttf", subset); + + Assert.IsNotNull(subset); + Assert.IsTrue(subset.MaxpTable.numGlyphs >= 3, + "Should have at least .notdef, space, a"); + } + + [TestMethod] + public void Subset_LargeText_ShouldCompleteQuickly() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var allLatinChars = Enumerable.Range(32, 95).Select(i => (char)i).ToArray(); + + var sw = System.Diagnostics.Stopwatch.StartNew(); + var subset = font.CreateSubset(allLatinChars); + sw.Stop(); + + SaveFont("edge_all_latin.ttf", subset); + + Assert.IsTrue(sw.ElapsedMilliseconds < 5000, + $"Subsetting took too long: {sw.ElapsedMilliseconds}ms"); + } + + [TestMethod] + public void Subset_DuplicateChars_ShouldDedup() + { + var font = TestFolderEngine.LoadFont("Roboto"); + + var subset1 = font.CreateSubset("aaa"); + var subset2 = font.CreateSubset("a"); + + Assert.AreEqual(subset1.MaxpTable.numGlyphs, subset2.MaxpTable.numGlyphs, + "Duplicate characters should result in same glyph count"); + } + + [TestMethod] + public void Subset_AllGlyphs_ShouldBeSimilarSizeToOriginal() + { + var font = TestFolderEngine.LoadFont("Roboto"); + + // Get ALL characters from cmap + var allChars = new HashSet(); + foreach (var subtable in font.CmapTable.SubTables) + { + var mappings = subtable.GetGlyphMappings().CharCodeToGlyphIndex; + foreach (var codepoint in mappings.Keys) + { + if (codepoint <= 0xFFFF) + allChars.Add((char)codepoint); + } + } + + var subset = font.CreateSubset(allChars); + + SaveFont("edge_full_subset.ttf", subset); + + // Subset with ALL glyphs should be similar size to original + var originalSize = font.Serialize().Length; + var subsetSize = subset.Serialize().Length; + + double ratio = (double)subsetSize / originalSize; + Assert.IsTrue(ratio > 0.8, + $"Full subset unexpectedly small: {ratio:P0} of original"); + } + + [TestMethod] + public void Subset_PreservesRobotoKerning() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var builder = new SubsetFontBuilder(); + + // Act + var subset = font.CreateSubset("AV"); + var shaper = new TextShaper(TestFolderEngine, subset); + var result = shaper.Shape("AV"); + + // Assert + Assert.IsTrue(result.Glyphs[0].XAdvance < font.HmtxTable.GetAdvanceWidth( + font.CmapTable.MapCharToGlyph('A')), + "Subset should preserve A-V kerning"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Subsetting/VerticalSubsettingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/VerticalSubsettingTests.cs new file mode 100644 index 0000000000..54c537386e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Subsetting/VerticalSubsettingTests.cs @@ -0,0 +1,179 @@ + /************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical subsetting tests (vhea/vmtx) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tests.Helpers; + +namespace EPPlus.Fonts.OpenType.Tests.Subsetting +{ + [TestClass] + public class VerticalSubsettingTests : FontTestBase + { + public override TestContext TestContext { get; set; } + + [ClassInitialize] + public static void ClassInitialize(TestContext ctx) + { + FontDirectoriesTestHelper.ClassInitialize(ctx); + } + + #region vhea/vmtx presence tests + + [TestMethod] + public void Subset_CjkFont_SubsetContainsVheaTable() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + Assert.IsNotNull(font.VheaTable, "BIZ UDGothic should have a vhea table"); + + // Act + var subset = font.CreateSubset("日本語"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert + Assert.IsNotNull(parsed.VheaTable, "Subset should contain vhea table"); + } + + [TestMethod] + public void Subset_CjkFont_SubsetContainsVmtxTable() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + Assert.IsNotNull(font.VmtxTable, "BIZ UDGothic should have a vmtx table"); + + // Act + var subset = font.CreateSubset("日本語"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert + Assert.IsNotNull(parsed.VmtxTable, "Subset should contain vmtx table"); + } + + [TestMethod] + public void Subset_FontWithoutVmtx_SubsetDoesNotContainVmtxTable() + { + // Arrange - Roboto has no vmtx/vhea + var font = TestFolderEngine.LoadFont("Roboto"); + Assert.IsNull(font.VmtxTable, "Roboto should not have a vmtx table"); + + // Act + var subset = font.CreateSubset("ABC"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + // Assert - vmtx should not be introduced by subsetting + Assert.IsNull(parsed.VmtxTable, "Subset of font without vmtx should not contain vmtx table"); + } + + #endregion + + #region vhea correctness tests + + [TestMethod] + public void Subset_CjkFont_VheaNumberOfVMetricsMatchesGlyphCount() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + + // Act + var subset = font.CreateSubset("日本語"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert - NumberOfVMetrics must equal numGlyphs (same simplification as hmtx) + Assert.AreEqual( + parsed.MaxpTable.numGlyphs, + parsed.VheaTable.NumberOfVMetrics, + "vhea.NumberOfVMetrics should equal numGlyphs in subset"); + } + + #endregion + + #region vmtx correctness tests + + [TestMethod] + public void Subset_CjkFont_VmtxAdvanceHeightPreservedForSubsettedGlyphs() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var text = "日"; + + // Get original glyph ID and advance height before subsetting + ushort originalGlyphId; + font.CmapTable.TryGetGlyphId('日', out originalGlyphId); + var originalAdvanceHeight = font.VmtxTable.GetAdvanceHeight(originalGlyphId); + + // Act + var subset = font.CreateSubset(text); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert - resolve new glyph ID in subset and verify advance height is preserved + ushort subsetGlyphId; + parsed.CmapTable.TryGetGlyphId('日', out subsetGlyphId); + var subsetAdvanceHeight = parsed.VmtxTable.GetAdvanceHeight(subsetGlyphId); + + Assert.AreEqual(originalAdvanceHeight, subsetAdvanceHeight, + $"AdvanceHeight for '日' should be preserved after subsetting " + + $"(original={originalAdvanceHeight}, subset={subsetAdvanceHeight})"); + } + + [TestMethod] + public void Subset_CjkFont_VmtxEntryCountMatchesGlyphCount() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + + // Act + var subset = font.CreateSubset("東京"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert - VMetrics count must equal numGlyphs + Assert.AreEqual( + parsed.MaxpTable.numGlyphs, + parsed.VmtxTable.VMetrics.Count, + "vmtx.VMetrics.Count should equal numGlyphs in subset"); + } + + [TestMethod] + public void Subset_CjkFont_PassesValidationAfterSubsetting() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + + // Act + var subset = font.CreateSubset("日本語テスト"); + var bytes = subset.Serialize(); + var parsed = new OpenTypeFont(bytes); + + SaveFontForCurrentTest(parsed); + + // Assert - full font validation should pass without errors + FontTestHelper.AssertFontValid(parsed, FontValidationSeverity.Warning); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TestAssemblySetup.cs b/src/EPPlus.Fonts.OpenType.Tests/TestAssemblySetup.cs new file mode 100644 index 0000000000..e9891b1000 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TestAssemblySetup.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Tests +{ + [TestClass] + public class TestAssemblySetup + { + [AssemblyInitialize] + public static void AssemblyInit(TestContext context) + { + OpenTypeFonts.ClearFontCache(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextFragmentCollectionTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextFragmentCollectionTests.cs new file mode 100644 index 0000000000..b9daa1f9fb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextFragmentCollectionTests.cs @@ -0,0 +1,308 @@ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Tests +{ + [TestClass] + public class TextFragmentCollectionTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void WrappingLongParagraphs() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var shaper = SystemFontsEngine.GetTextShaper("Aptos Narrow", FontSubFamily.Regular); + var layout = new TextLayoutEngine(shaper); + + var outputLines = layout.WrapText( + "Hello World! a b c d e f g h i j k l m n o p q r s t u v w x y z \r\n", + 28f, + 225); + + Assert.AreEqual("Hello World! a b c d", outputLines[0]); + Assert.AreEqual("e f g h i j k l m n o p q", outputLines[1]); + Assert.AreEqual("r s t u v w x y z ", outputLines[2]); + } + + //TODO: DOUBLE-CHECK BOLD+ITALIC for narrow later it seems innaccurate + [TestMethod] + public void MeasureBold() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + string test = "TextBox2"; + + var measurer = SystemFontsEngine.GetShaperForFont(font2); + var widthInPoints = measurer.ShapeLight(test).GetWidthInPoints(font2.Size); + + var inPixels = Math.Round(widthInPoints.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + Assert.AreEqual(54, inPixels); + } + + [TestMethod] + public void MeasureGoudy() + { + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + var text = "Goudy size"; + + var measurer = SystemFontsEngine.GetShaperForFont(font5); + + var widthInPoints = measurer.ShapeLight(text).GetWidthInPoints(16f); + + var inPixels = Math.Round(widthInPoints.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + Assert.AreEqual(237, inPixels); + } + + [TestMethod] + public void MeasureWrappedWidthsWithInternalLineBreaks() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + List lstOfRichText = new() { "TextBox\r\na\r\n", "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + + var font1 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + var font6 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 24, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new() { font1, font2, font3, font4, font5, font6 }; + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + var ttMeasurer = SystemFontsEngine.GetTextLayoutEngineForFont(font1); + + var textFragments = new TextFragmentCollectionSimple(fonts, lstOfRichText); + + var wrappedLines = ttMeasurer.WrapRichTextLines(textFragments, maxSizePoints); + + var line1 = wrappedLines[0]; + + var pixels11 = Math.Round(line1.InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeline1 = Math.Round(line1.Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + Assert.AreEqual(44, pixels11); + Assert.AreEqual(pixels11, pixelsWholeline1); + + var line2 = wrappedLines[1]; + + var pixels21 = Math.Round(line2.InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeline2 = Math.Round(line2.Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + Assert.AreEqual(7, pixels21); + Assert.AreEqual(pixels21, pixelsWholeline2); + + var line3 = wrappedLines[2]; + + var pixels31 = Math.Round(line3.InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels32 = Math.Round(line3.InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels33 = Math.Round(line3.InternalLineFragments[2].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine3 = Math.Round(line3.Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + //~54 px + Assert.AreEqual(54, pixels31); + //~70 px aka 51.75pt + Assert.AreEqual(70, pixels32); + //~16-17 px This line contains a space at the end + Assert.AreEqual(17, pixels33); + + //Total Width: ~140 + Assert.AreEqual(140d, pixelsWholeLine3); + + var line4 = wrappedLines[3]; + + var pixels41 = Math.Round(line4.InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels42 = Math.Round(line4.InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine4 = Math.Round(line4.Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + //~34 px + Assert.AreEqual(33, pixels41); + // This line contains a space at the end + Assert.AreEqual(248, pixels42); + + Assert.AreEqual(281, pixelsWholeLine4); + + var line5 = wrappedLines[4]; + + var pixels51 = Math.Round(line5.InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels52 = Math.Round(line5.InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine5 = Math.Round(line5.Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + Assert.AreEqual(35, pixels51); + //This line does NOT contain a space at the end + Assert.AreEqual(134, pixels52); + + Assert.AreEqual(169, pixelsWholeLine5); + } + + [TestMethod] + public void MeasureWrappedWidths() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Bold); + RequireFont(SystemFontsEngine, "Goudy Stout", FontSubFamily.Regular); + + List lstOfRichText = new() { "TextBox2", "ra underline", "La Strike", "Goudy size 16", "SvgSize 24" }; + + var font2 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Bold + }; + + var font3 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Underline + }; + + var font4 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Strikeout + }; + + var font5 = new MeasurementFont() + { + FontFamily = "Goudy Stout", + Size = 16, + Style = MeasurementFontStyles.Regular + }; + + var font6 = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 24, + Style = MeasurementFontStyles.Regular + }; + + List fonts = new() { font2, font3, font4, font5, font6 }; + + var maxSizePoints = Math.Round(300d, 0, MidpointRounding.AwayFromZero).PixelToPoint(); + var ttMeasurer = SystemFontsEngine.GetTextLayoutEngineForFont(font2); + + var textFragments = new TextFragmentCollectionSimple(fonts, lstOfRichText); + + var wrappedLines = ttMeasurer.WrapRichTextLines(textFragments, maxSizePoints); + + var pixels1 = Math.Round(wrappedLines[0].InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels2 = Math.Round(wrappedLines[0].InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels3 = Math.Round(wrappedLines[0].InternalLineFragments[2].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine = Math.Round(wrappedLines[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + + //~54 px + Assert.AreEqual(54, pixels1); + //~70 px aka 51.75pt + Assert.AreEqual(70, pixels2); + //~16-17 px This line contains a space at the end + Assert.AreEqual(17, pixels3); + + //Total Width: ~140 + Assert.AreEqual(140d, pixelsWholeLine); + + var pixels21 = Math.Round(wrappedLines[1].InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels22 = Math.Round(wrappedLines[1].InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine2 = Math.Round(wrappedLines[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + //~34 px + Assert.AreEqual(33, pixels21); + // This line contains a space at the end + Assert.AreEqual(248, pixels22); + + Assert.AreEqual(281, pixelsWholeLine2); + + var pixels31 = Math.Round(wrappedLines[2].InternalLineFragments[0].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixels32 = Math.Round(wrappedLines[2].InternalLineFragments[1].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + var pixelsWholeLine3 = Math.Round(wrappedLines[2].Width.PointToPixel(), 0, MidpointRounding.AwayFromZero); + Assert.AreEqual(35, pixels31); + //This line does NOT contain a space at the end + Assert.AreEqual(134, pixels32); + + Assert.AreEqual(169, pixelsWholeLine3); + } + + [TestMethod] + public void CorrectTextLinesAreReturnedWhenSmallMaxWidth() + { + RequireFont(SystemFontsEngine, "Aptos Narrow", FontSubFamily.Regular); + + var defaultFont = new MeasurementFont() + { + FontFamily = "Aptos Narrow", + Size = 11, + Style = MeasurementFontStyles.Regular + }; + + var ttMeasurer = SystemFontsEngine.GetTextLayoutEngineForFont(defaultFont); + + var txt = "This is my text"; + + //This should be small enough to put each word on a new row. + var maxWidth = 21.5d; + + var txtLines = ttMeasurer.WrapText(txt, 11f, maxWidth); + + Assert.AreEqual(4, txtLines.Count); + Assert.AreEqual("This", txtLines[0]); + Assert.AreEqual("is", txtLines[1]); + Assert.AreEqual("my", txtLines[2]); + Assert.AreEqual("text", txtLines[3]); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ChainingContextualSubstitutionTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ChainingContextualSubstitutionTests.cs new file mode 100644 index 0000000000..49b793c6d6 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ChainingContextualSubstitutionTests.cs @@ -0,0 +1,135 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using EPPlus.Fonts.OpenType.TextShaping; +using System.Linq; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class ChainingContextualSubstitutionTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + #region Roboto ffi Ligature Tests (Type 6 Contextual) + + [TestMethod] + public void ChainingContextual_Roboto_FfiLigature_Office() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.Shape("office"); + + // Assert - Expected: 'o' + 'ffi' ligature + 'c' + 'e' = 4 glyphs + Assert.AreEqual(4, result.Glyphs.Length, "Should have 4 glyphs: o, ffi, c, e"); + Assert.AreEqual(3, result.Glyphs[1].CharCount, "ffi ligature should represent 3 characters"); + } + + [TestMethod] + public void ChainingContextual_Roboto_FfiLigature_AtStart() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act - ffi at the beginning of text (no backtrack context) + var result = shaper.Shape("fficer"); + + // Assert - Expected: 'ffi' ligature + 'c' + 'e' + 'r' = 4 glyphs + Assert.AreEqual(4, result.Glyphs.Length, "Should have 4 glyphs: ffi, c, e, r"); + Assert.AreEqual(3, result.Glyphs[0].CharCount, "ffi ligature should represent 3 characters"); + } + + [TestMethod] + public void ChainingContextual_Roboto_FfiLigature_AtEnd() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act - ffi at the end of text (no lookahead context) + var result = shaper.Shape("offi"); + + // Assert - Expected: 'o' + 'ffi' ligature = 2 glyphs + Assert.AreEqual(2, result.Glyphs.Length, "Should have 2 glyphs: o, ffi"); + Assert.AreEqual(3, result.Glyphs[1].CharCount, "ffi ligature should represent 3 characters"); + } + + [TestMethod] + public void ChainingContextual_Roboto_MultipleFfiLigatures() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act - Multiple ffi sequences in same text + var result = shaper.Shape("office officer"); + + // Assert - Expected: 'o' + 'ffi' + 'c' + 'e' + ' ' + 'o' + 'ffi' + 'c' + 'e' + 'r' = 10 glyphs + Assert.AreEqual(10, result.Glyphs.Length); + Assert.AreEqual(3, result.Glyphs[1].CharCount, "First ffi ligature"); + Assert.AreEqual(3, result.Glyphs[6].CharCount, "Second ffi ligature"); + } + + #endregion + + #region Type 6 vs Type 4 Interaction + + [TestMethod] + public void ChainingContextual_Roboto_Type6BeforeType4_CorrectOrder() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var subset = font.CreateSubset("office fit"); + var shaper = new TextShaper(TestFolderEngine,subset); + + // Act - Text with both ffi (Type 6) and fi (Type 4) ligatures + var result = shaper.Shape("office fit"); + + // Assert - Expected: 'o' + 'ffi' + 'c' + 'e' + ' ' + 'fi' + 't' = 7 glyphs + Assert.AreEqual(7, result.Glyphs.Length); + Assert.AreEqual(3, result.Glyphs[1].CharCount, "ffi from Type 6 contextual"); + Assert.AreEqual(2, result.Glyphs[5].CharCount, "fi from Type 4 simple"); + } + + #endregion + + #region Metrics Validation + + [TestMethod] + public void ChainingContextual_Roboto_FfiLigature_HasCorrectMetrics() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var result = shaper.Shape("ffi"); + + // Assert + Assert.AreEqual(1, result.Glyphs.Length, "Should be single ffi ligature"); + + var ffiGlyph = result.Glyphs[0]; + Assert.IsTrue(ffiGlyph.XAdvance > 0, "ffi ligature should have positive advance width"); + Assert.AreEqual(0, ffiGlyph.YAdvance, "Horizontal text should have zero Y advance"); + Assert.AreEqual(0, ffiGlyph.ClusterIndex, "Should start at cluster 0"); + Assert.AreEqual(3, ffiGlyph.CharCount, "Should represent 3 characters"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/MarkToBaseTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/MarkToBaseTests.cs new file mode 100644 index 0000000000..337e76e8c0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/MarkToBaseTests.cs @@ -0,0 +1,41 @@ +using EPPlus.Fonts.OpenType.FontResolver; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class MarkToBaseTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestInitialize] + public void TestSetup() + { + OpenTypeFonts.ClearFontCache(); + + } + + [TestMethod] + public void MarkToBaseTest() + { + var font = TestFolderEngine.LoadFont("EB Garamond", FontSubFamily.Regular, ignoreCache: true); + + var shaper = new TextShaper(TestFolderEngine,font); + string test = "e\u0301"; // e + combining acute + + var shaped = shaper.Shape(test, ShapingOptions.Full); + + Assert.IsTrue(shaped.Glyphs.Any(x => x.XOffset != 0), + $"Expected XOffset != 0. Got: {string.Join(", ", shaped.Glyphs.Select(g => $"X={g.XOffset}"))}"); + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ShapeLightTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ShapeLightTests.cs new file mode 100644 index 0000000000..adc209f87c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/ShapeLightTests.cs @@ -0,0 +1,242 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 03/18/2026 EPPlus Software AB ShapeLight multi-font tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.TextShaping; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class ShapeLightTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void ShapeLight_SimpleText_ReturnsSameGlyphCountAsShape() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var full = shaper.Shape("Hello"); + var light = shaper.ShapeLight("Hello"); + + // Assert + Assert.AreEqual(full.Glyphs.Length, light.Glyphs.Length, + "ShapeLight should produce same number of glyphs as Shape"); + } + + [TestMethod] + public void ShapeLight_SimpleText_HasFontUnitsPerEm() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var result = shaper.ShapeLight("Hello"); + + // Assert + Assert.IsNotNull(result.FontUnitsPerEm, "Should have FontUnitsPerEm"); + Assert.AreEqual(1, result.FontUnitsPerEm.Length, "Single font should have 1 entry"); + Assert.AreEqual(font.HeadTable.UnitsPerEm, result.FontUnitsPerEm[0]); + } + + [TestMethod] + public void ShapeLight_EmojiOnly_UsesFallbackFont() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeLight("😀😁😂"); + + // Assert + Assert.AreEqual(3, result.Glyphs.Length, "Should have 3 glyphs for 3 emojis"); + Assert.IsNotNull(result.FontUnitsPerEm); + Assert.IsTrue(result.FontUnitsPerEm.Length >= 2, "Should have at least primary + emoji fallback"); + + // Primary font is always registered at FontId 0. Emoji glyphs come from a fallback, + // so they should have FontId != 0. + foreach (var glyph in result.Glyphs) + { + Assert.AreNotEqual(0, glyph.FontId, "Emoji glyphs should come from fallback, not primary"); + Assert.IsTrue(glyph.XAdvance > 0, "Emoji glyphs should have positive width"); + } + } + + [TestMethod] + public void ShapeLight_MixedTextAndEmoji_HasMultipleFonts() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeLight("Hi 😀 there"); + + // Assert + Assert.IsNotNull(result.FontUnitsPerEm); + Assert.AreEqual(2, result.FontUnitsPerEm.Length, + "Should have 2 fonts (primary + emoji fallback)"); + + // Verify emoji glyph has different FontId than text glyphs + var textFontId = result.Glyphs[0].FontId; + var emojiFontId = result.Glyphs.First(g => g.ClusterIndex == 3).FontId; // '😀' starts at index 3 + Assert.AreNotEqual(textFontId, emojiFontId, + "Emoji should use different font than text"); + } + + [TestMethod] + public void ShapeLight_GetWidthInPoints_ConsistentWithShape() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + float fontSize = 12f; + + // Act + var full = shaper.Shape("Hello World"); + float fullWidth = full.GetWidthInPoints(fontSize); + + var light = shaper.ShapeLight("Hello World"); + float lightWidth = light.GetWidthInPoints(fontSize); + + // Assert — ShapeLight uses simplified kerning so allow small difference + Assert.AreEqual(fullWidth, lightWidth, fullWidth * 0.05f, + "ShapeLight width should be within 5% of Shape width"); + } + + [TestMethod] + public void ShapeLight_FillCharWidths_ProducesCorrectWidths() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + string text = "ABC"; + float fontSize = 12f; + var charWidths = new double[text.Length]; + + // Act + var result = shaper.ShapeLight(text); + result.FillCharWidths(fontSize, charWidths, text.Length); + + // Assert + for (int i = 0; i < text.Length; i++) + { + Assert.IsTrue(charWidths[i] > 0, + $"Character '{text[i]}' at index {i} should have positive width"); + } + + // Total of char widths should match GetWidthInPoints + double totalCharWidths = charWidths.Sum(); + float shapedWidth = result.GetWidthInPoints(fontSize); + Assert.AreEqual(shapedWidth, totalCharWidths, 0.01, + "Sum of char widths should match total shaped width"); + } + + [TestMethod] + public void ShapeLight_FillCharWidths_MixedEmoji_CorrectPerGlyphScale() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + string text = "A😀B"; + float fontSize = 12f; + var charWidths = new double[text.Length]; + + // Act + var result = shaper.ShapeLight(text); + result.FillCharWidths(fontSize, charWidths, text.Length); + + // Assert + Assert.IsTrue(charWidths[0] > 0, "'A' should have positive width"); + // charWidths[1] is high surrogate of emoji — should have the emoji width + Assert.IsTrue(charWidths[1] > 0, "Emoji (at surrogate position) should have positive width"); + // charWidths[2] is low surrogate — typically 0 (width is on the high surrogate) + // charWidths[3] is 'B' + Assert.IsTrue(charWidths[text.Length - 1] > 0, "'B' should have positive width"); + + // Total should match + double totalCharWidths = charWidths.Sum(); + float shapedWidth = result.GetWidthInPoints(fontSize); + Assert.AreEqual(shapedWidth, totalCharWidths, 0.01, + "Sum of char widths should match total shaped width"); + } + + [TestMethod] + public void ShapeLight_EmptyString_ReturnsEmptyResult() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeLight(""); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Glyphs.Length); + Assert.IsNotNull(result.FontUnitsPerEm); + Assert.AreEqual(0f, result.GetWidthInPoints(12f)); + } + + [TestMethod] + public void ShapeLight_TextEmojiAndMath_UsesThreeFonts() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // U+1D400 = 𝐀 (Mathematical Bold Capital A) — not in Roboto or Noto Emoji, + // should fall back to Noto Sans Math. + // If U+1D400 isn't covered, try U+2200 (∀) or U+222B (∫). + string mathChar = "\u2200"; + string text = "Hi😀" + mathChar; + float fontSize = 12f; + + // Act + var result = shaper.ShapeLight(text); + + // Assert — three distinct fonts + Assert.IsNotNull(result.FontUnitsPerEm); + Assert.AreEqual(3, result.FontUnitsPerEm.Length, + $"Expected 3 fonts (primary + emoji + math), got {result.FontUnitsPerEm.Length}"); + + // Verify three distinct FontIds are present + var distinctFontIds = result.Glyphs.Select(g => g.FontId).Distinct().OrderBy(id => id).ToArray(); + Assert.AreEqual(3, distinctFontIds.Length, + $"Expected 3 distinct FontIds, got [{string.Join(", ", distinctFontIds)}]"); + + // All glyphs should have valid (non-zero) advance widths + foreach (var glyph in result.Glyphs) + { + Assert.IsTrue(glyph.XAdvance > 0, + $"Glyph at ClusterIndex {glyph.ClusterIndex} (FontId={glyph.FontId}) should have positive width"); + } + + // FillCharWidths should still sum correctly + var charWidths = new double[text.Length]; + result.FillCharWidths(fontSize, charWidths, text.Length); + double totalCharWidths = charWidths.Sum(); + float shapedWidth = result.GetWidthInPoints(fontSize); + Assert.AreEqual(shapedWidth, totalCharWidths, 0.01, + "Sum of char widths should match total shaped width across all three fonts"); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleAdjustmentsTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleAdjustmentsTests.cs new file mode 100644 index 0000000000..b8800e80d8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleAdjustmentsTests.cs @@ -0,0 +1,206 @@ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.TextShaping; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class SingleAdjustmentTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void SingleAdjustment_Roboto_DoesNotCrash() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + var result = shaper.Shape("Hello World"); + + Assert.IsNotNull(result); + Assert.IsTrue(result.Glyphs.Length > 0); + Assert.AreEqual("Hello World", result.OriginalText); + } + + [TestMethod] + public void SingleAdjustment_WithZeroValues_DoesNotAffectOutput() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + var withPositioning = shaper.Shape("AV"); + var withoutPositioning = shaper.Shape("AV", ShapingOptions.None); + + Assert.AreEqual(withoutPositioning.Glyphs.Length, withPositioning.Glyphs.Length); + Assert.IsTrue(withPositioning.TotalAdvanceWidth < withoutPositioning.TotalAdvanceWidth, + "Should have kerning applied"); + } + + [TestMethod] + public void SingleAdjustment_WithZeroValues_DoesNotAffectOutput2() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + var withPositioning = shaper.Shape("AV"); + var withoutPositioning = shaper.Shape("AV", ShapingOptions.None); + + Debug.WriteLine($"Without positioning: {withoutPositioning.TotalAdvanceWidth}"); + Debug.WriteLine($"With positioning: {withPositioning.TotalAdvanceWidth}"); + Debug.WriteLine($"Difference: {withoutPositioning.TotalAdvanceWidth - withPositioning.TotalAdvanceWidth}"); + + Debug.WriteLine("\nWithout positioning glyphs:"); + foreach (var g in withoutPositioning.Glyphs) + Debug.WriteLine($" GlyphId: {g.GlyphId}, XAdvance: {g.XAdvance}, XOffset: {g.XOffset}"); + + Debug.WriteLine("\nWith positioning glyphs:"); + foreach (var g in withPositioning.Glyphs) + Debug.WriteLine($" GlyphId: {g.GlyphId}, XAdvance: {g.XAdvance}, XOffset: {g.XOffset}"); + + Assert.AreEqual(withoutPositioning.Glyphs.Length, withPositioning.Glyphs.Length); + Assert.IsTrue(withPositioning.TotalAdvanceWidth < withoutPositioning.TotalAdvanceWidth, + "Should have kerning applied"); + } + + [TestMethod] + public void Kerning_IsApplied_ForAVPair() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + var optionsOnlyKern = new ShapingOptions + { + ApplySubstitutions = false, + ApplyPositioning = true, + GposFeatures = new List { "kern" }, + Script = "latn", + Language = null + }; + + var withoutKerning = shaper.Shape("AV", ShapingOptions.None); + var withKerning = shaper.Shape("AV", optionsOnlyKern); + + Assert.IsTrue(withKerning.TotalAdvanceWidth < withoutKerning.TotalAdvanceWidth, + "Kerning should reduce advance width for AV pair"); + } + + [TestMethod] + public void SingleAdjustment_Verdana_HasRealAdjustments() + { + try + { + var font = SystemFontsEngine.LoadFont("Verdana"); + if (font == null || font.FullName != "Verdana") + { + Assert.Inconclusive("Verdana font not found - test skipped"); + return; + } + var shaper = new TextShaper(SystemFontsEngine, font); + + var withPositioning = shaper.Shape("Hello123"); + var withoutPositioning = shaper.Shape("Hello123", ShapingOptions.None); + + Assert.IsNotNull(withPositioning); + Assert.IsNotNull(withoutPositioning); + Assert.AreEqual(withPositioning.Glyphs.Length, withoutPositioning.Glyphs.Length); + + bool hasXOffset = false; + for (int i = 0; i < withPositioning.Glyphs.Length; i++) + { + if (withPositioning.Glyphs[i].XOffset != 0) + { + hasXOffset = true; + System.Console.WriteLine($"Glyph {i} (GID={withPositioning.Glyphs[i].GlyphId}) has XOffset={withPositioning.Glyphs[i].XOffset}"); + } + } + + System.Console.WriteLine($"Found XOffset adjustments: {hasXOffset}"); + } + catch (System.IO.FileNotFoundException) + { + Assert.Inconclusive("Verdana font not found - test skipped"); + } + } + + [TestMethod] + public void SingleAdjustment_Verdana_AdjustmentsAppliedWithDefaultOptions() + { + try + { + var font = SystemFontsEngine.LoadFont("Verdana"); + if (font == null || font.FullName != "Verdana") + { + Assert.Inconclusive("Verdana font not found - test skipped"); + return; + } + var shaper = new TextShaper(SystemFontsEngine, font); + + var result = shaper.Shape("Test"); + + Assert.IsNotNull(result); + Assert.AreEqual(4, result.Glyphs.Length); + Assert.AreEqual("Test", result.OriginalText); + } + catch (System.IO.FileNotFoundException) + { + Assert.Inconclusive("Verdana font not found - test skipped"); + } + } + + [TestMethod] + public void SingleAdjustment_AppliedBeforeKerning() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + var result = shaper.Shape("Test"); + + Assert.IsNotNull(result); + Assert.IsTrue(result.Glyphs.Length > 0); + } + + [TestMethod] + public void SingleAdjustment_NotAppliedWithNoneOptions() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + var result = shaper.Shape("Test", ShapingOptions.None); + + Assert.IsNotNull(result); + Assert.AreEqual(4, result.Glyphs.Length); + + foreach (var glyph in result.Glyphs) + { + Assert.AreEqual(0, glyph.XOffset, "No offset adjustments with None options"); + Assert.AreEqual(0, glyph.YOffset, "No offset adjustments with None options"); + } + } + + [TestMethod] + public void SingleAdjustmentProvider_HandlesNullFont() + { + var font = TestFolderEngine.LoadFont("SourceSans3"); + var shaper = new TextShaper(TestFolderEngine,font); + + var result = shaper.Shape("Test"); + + Assert.IsNotNull(result); + Assert.AreEqual(4, result.Glyphs.Length); + } + + // NOTE: Verdana Single Adjustment coverage includes 397 glyphs across 3 Format 2 subtables + // with XPlacement=36. This is likely for superscript or special positioning features. + // To fully test these, we would need to: + // 1. Identify which specific characters map to the adjusted glyphs + // 2. Verify the XOffset is correctly applied (should be 36 font units) + // 3. Test interaction with kerning (Single Adjustment first, then kerning) + // + // For now, these tests verify that: + // - The code doesn't crash with real Single Adjustment data + // - Options are respected + // - Both zero-value (Roboto) and non-zero (Verdana) cases work + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleSubstitutionTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleSubstitutionTests.cs new file mode 100644 index 0000000000..19fa6e1004 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/SingleSubstitutionTests.cs @@ -0,0 +1,199 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/19/2026 EPPlus Software AB Single Substitution tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using EPPlus.Fonts.OpenType.TextShaping; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class SingleSubstitutionTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void SingleSubstitution_SmallCaps_SubstitutesGlyphs() + { + // NOTE: This test requires a font with small caps feature (smcp) + // Common fonts with smcp: Georgia, Garamond, Calibri, Cambria + + var fontNames = new[] { "Roboto" }; + + foreach (var fontName in fontNames) + { + try + { + var font = TestFolderEngine.LoadFont(fontName, FontSubFamily.Regular); + + // Verify font has smcp feature with Type 1 lookup + if (font == null || !font.FullName.Contains(fontName) || font.GsubTable == null) + continue; + + bool hasSmcpWithType1 = false; + foreach (var featureRecord in font.GsubTable.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "smcp") + { + var feature = featureRecord.FeatureTable; + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < font.GsubTable.LookupList.Lookups.Count) + { + var lookup = font.GsubTable.LookupList.Lookups[lookupIndex]; + DebugWriteLine($"{fontName} smcp uses Lookup Type {lookup.LookupType}"); + if (lookup.LookupType == 1) + { + hasSmcpWithType1 = true; + } + } + } + } + } + + if (!hasSmcpWithType1) + { + DebugWriteLine($"{fontName} has smcp but not with Type 1 lookup - skipping"); + continue; + } + + // Found a font with smcp using Type 1! + var shaper = new TextShaper(TestFolderEngine, font); + + // Act - lowercase letters should become small caps + var normal = shaper.Shape("hello", ShapingOptions.Default); + var smallCaps = shaper.Shape("hello", new ShapingOptions + { + ApplySubstitutions = true, + GsubFeatures = new List { "smcp" }, + ApplyPositioning = true + }); + + // Assert - At least one glyph should be substituted + bool anySubstituted = false; + for (int i = 0; i < normal.Glyphs.Length; i++) + { + if (normal.Glyphs[i].GlyphId != smallCaps.Glyphs[i].GlyphId) + { + anySubstituted = true; + DebugWriteLine($"{fontName}: '{normal.OriginalText[i]}' GID {normal.Glyphs[i].GlyphId} → {smallCaps.Glyphs[i].GlyphId}"); + } + } + + Assert.IsTrue(anySubstituted, + $"{fontName} has smcp feature but no glyphs were substituted for 'hello'"); + + DebugWriteLine($"✓ {fontName}: Small caps working!"); + return; // Test passed, no need to try other fonts + } + catch (System.IO.FileNotFoundException) + { + continue; // Try next font + } + } + + Assert.Inconclusive("No font with working small caps (Type 1) found. Tested: " + string.Join(", ", fontNames)); + } + + + + [TestMethod] + public void SingleSubstitution_AppliesBeforeLigatures() + { + // Test that single substitution happens before ligature formation + // This is important: if we request both smcp and liga, small caps should apply first + + var fontNames = new[] { "Roboto" }; + + foreach (var fontName in fontNames) + { + try + { + var font = TestFolderEngine.LoadFont(fontName); + + if (font == null || !font.FullName .Contains(fontName) || font.GsubTable == null) + continue; + + bool hasSmcpWithType1 = false; + bool hasLiga = false; + + foreach (var featureRecord in font.GsubTable.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "smcp") + { + var feature = featureRecord.FeatureTable; + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < font.GsubTable.LookupList.Lookups.Count) + { + var lookup = font.GsubTable.LookupList.Lookups[lookupIndex]; + if (lookup.LookupType == 1) + { + hasSmcpWithType1 = true; + } + } + } + } + else if (featureRecord.FeatureTag.Value == "liga") + { + hasLiga = true; + } + } + + if (!hasSmcpWithType1 || !hasLiga) + continue; + + var shaper = new TextShaper(TestFolderEngine, font); + + // Act - Apply both features (single substitution should happen first) + var bothFeatures = shaper.Shape("office", new ShapingOptions + { + ApplySubstitutions = true, + GsubFeatures = new List { "smcp", "liga" }, + ApplyPositioning = true + }); + + var onlySmcp = shaper.Shape("office", new ShapingOptions + { + ApplySubstitutions = true, + GsubFeatures = new List { "smcp" }, + ApplyPositioning = true + }); + + // Assert - Should not crash, glyphs should be processed + Assert.IsNotNull(bothFeatures); + Assert.IsNotNull(onlySmcp); + + DebugWriteLine($"✓ {fontName}: Feature ordering test passed"); + return; + } + catch (System.IO.FileNotFoundException) + { + continue; + } + } + + Assert.Inconclusive("No font with both smcp (Type 1) and liga features found"); + } + + private void DebugWriteLine(string message) + { + Debug.WriteLine(message); + TestContext?.WriteLine(message); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/TextShaperTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/TextShaperTests.cs new file mode 100644 index 0000000000..80382fce9d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/TextShaperTests.cs @@ -0,0 +1,883 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/16/2025 EPPlus Software AB TextShaper tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using EPPlus.Fonts.OpenType.TextShaping; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tests.TextShaping +{ + [TestClass] + public class TextShaperTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + #region Basic Shaping Tests + + [TestMethod] + public void Shape_EmptyString_ReturnsEmptyResult() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var shaped = shaper.Shape(""); + + // Assert + Assert.IsNotNull(shaped); + Assert.AreEqual("", shaped.OriginalText); + Assert.AreEqual(0, shaped.Glyphs.Length); + Assert.AreEqual(0, shaped.TotalAdvanceWidth); + } + + [TestMethod] + public void Shape_NullString_ReturnsEmptyResult() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape(null); + + // Assert + Assert.IsNotNull(shaped); + Assert.AreEqual("", shaped.OriginalText); + Assert.AreEqual(0, shaped.Glyphs.Length); + } + + [TestMethod] + public void Shape_SingleCharacter_ReturnsOneGlyph() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("A"); + + // Assert + Assert.IsNotNull(shaped); + Assert.AreEqual("A", shaped.OriginalText); + Assert.AreEqual(1, shaped.Glyphs.Length); + Assert.IsTrue(shaped.Glyphs[0].GlyphId > 0, "Should have valid glyph ID"); + Assert.IsTrue(shaped.Glyphs[0].XAdvance > 0, "Should have positive advance width"); + } + + [TestMethod] + public void Shape_SimpleWord_ReturnsCorrectGlyphCount() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var shaped = shaper.Shape("Hello"); + + // Assert + Assert.IsNotNull(shaped); + Assert.AreEqual("Hello", shaped.OriginalText); + Assert.AreEqual(5, shaped.Glyphs.Length); + Assert.IsTrue(shaped.TotalAdvanceWidth > 0); + } + + [TestMethod] + public void Shape_WithSpace_IncludesSpaceGlyph() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var shaped = shaper.Shape("A B"); + + // Assert + Assert.AreEqual(3, shaped.Glyphs.Length); + Assert.IsTrue(shaped.Glyphs[1].XAdvance > 0, "Space should have advance width"); + } + + #endregion + + #region Kerning Tests + + [TestMethod] + public void Shape_WithKerning_ReducesWidth() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + var withKerning = shaper.Shape("WAVE", ShapingOptions.Default); + var withoutKerning = shaper.Shape("WAVE", ShapingOptions.None); + + // Assert + Assert.IsTrue(withKerning.TotalAdvanceWidth < withoutKerning.TotalAdvanceWidth, + "Kerning should reduce width for 'WAVE'"); + } + + [TestMethod] + public void Debug_GposKerningFormat() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + + Assert.IsNotNull(font.GposTable, "Should have GPOS"); + + // Find kern feature + foreach (var featureRecord in font.GposTable.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "kern") + { + Debug.WriteLine("Found 'kern' feature"); + + var feature = featureRecord.FeatureTable; + foreach (var lookupIndex in feature.LookupListIndices) + { + var lookup = font.GposTable.LookupList.Lookups[lookupIndex]; + Debug.WriteLine($"Lookup type: {lookup.LookupType}"); + + foreach (var subtable in lookup.SubTables) + { + Debug.WriteLine($"Subtable type: {subtable.GetType().Name}"); + + if (subtable is PairPosSubTableFormat1 format1) + { + Debug.WriteLine($" Format 1: {format1.PairSets.Count} pair sets"); + } + else if (subtable is PairPosSubTableFormat2 format2) + { + Debug.WriteLine($" Format 2: Class-based kerning"); + Debug.WriteLine($" ClassDef1 glyphs: {format2.ClassDef1?.GetType().Name}"); + Debug.WriteLine($" ClassDef2 glyphs: {format2.ClassDef2?.GetType().Name}"); + Debug.WriteLine($" Class1 count: {format2.Class1Count}"); + Debug.WriteLine($" Class2 count: {format2.Class2Count}"); + } + } + } + } + } + } + + [TestMethod] + public void Shape_AVPair_HasNegativeKerning() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + var withKerning = shaper.Shape("AV"); + var withoutKerning = shaper.Shape("AV", ShapingOptions.None); + + // Assert + Assert.IsTrue(withKerning.TotalAdvanceWidth < withoutKerning.TotalAdvanceWidth, + "A-V pair should have negative kerning"); + + // Check that first glyph (A) has reduced advance + Assert.IsTrue(withKerning.Glyphs[0].XAdvance < withoutKerning.Glyphs[0].XAdvance, + "First glyph should have kerning applied"); + } + + [TestMethod] + public void Shape_FastOption_StillAppliesKerning() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + var fast = shaper.Shape("WAVE", ShapingOptions.Fast); + var none = shaper.Shape("WAVE", ShapingOptions.None); + + // Assert + Assert.IsTrue(fast.TotalAdvanceWidth < none.TotalAdvanceWidth, + "Fast option should still apply kerning"); + } + + #endregion + + #region Measurement Tests + + [TestMethod] + public void MeasureTextInPoints_ReturnsReasonableValue() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + float width = shaper.MeasureTextInPoints("Hello", 12); + + // Assert + Assert.IsTrue(width > 10, "Should be at least 10 points wide"); + Assert.IsTrue(width < 100, "Should be less than 100 points wide"); + } + + [TestMethod] + public void MeasureTextInPixels_ScalesWithDpi() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + float width72 = shaper.MeasureTextInPixels("Hello", 12, 72); + float width96 = shaper.MeasureTextInPixels("Hello", 12, 96); + + // Assert + Assert.IsTrue(width96 > width72, "96 DPI should be wider than 72 DPI"); + Assert.AreEqual(96.0f / 72.0f, width96 / width72, 0.01, "Should scale proportionally"); + } + + [TestMethod] + public void MeasureText_LargerFontSize_LargerWidth() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + float width12 = shaper.MeasureTextInPoints("Hello", 12); + float width24 = shaper.MeasureTextInPoints("Hello", 24); + + // Assert + Assert.IsTrue(width24 > width12 * 1.9, "24pt should be ~2x wider than 12pt"); + Assert.IsTrue(width24 < width12 * 2.1, "24pt should be ~2x wider than 12pt"); + } + + #endregion + + #region Glyph Properties Tests + + [TestMethod] + public void Shape_GlyphsHaveClusterIndices() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("ABC"); + + // Assert + Assert.AreEqual(0, shaped.Glyphs[0].ClusterIndex); + Assert.AreEqual(1, shaped.Glyphs[1].ClusterIndex); + Assert.AreEqual(2, shaped.Glyphs[2].ClusterIndex); + } + + [TestMethod] + public void Shape_GlyphsHaveCharCount() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("ABC"); + + // Assert + foreach (var glyph in shaped.Glyphs) + { + Assert.AreEqual(1, glyph.CharCount, "Simple glyphs should have CharCount=1"); + } + } + + [TestMethod] + public void Shape_GlyphsHaveValidIds() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("Hello"); + + // Assert + foreach (var glyph in shaped.Glyphs) + { + Assert.IsTrue(glyph.GlyphId < font.MaxpTable.numGlyphs, + "Glyph ID should be within font bounds"); + } + } + + #endregion + + #region Multi-line Tests + + [TestMethod] + public void ShapeLines_SingleLine_ReturnsOneElement() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var lines = shaper.ShapeLines("Hello"); + + // Assert + Assert.AreEqual(1, lines.Length); + Assert.AreEqual("Hello", lines[0].OriginalText); + } + + [TestMethod] + public void ShapeLines_TwoLinesWithLF_ReturnsTwoElements() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var lines = shaper.ShapeLines("Hello\nWorld"); + + // Assert + Assert.AreEqual(2, lines.Length); + Assert.AreEqual("Hello", lines[0].OriginalText); + Assert.AreEqual("World", lines[1].OriginalText); + } + + [TestMethod] + public void ShapeLines_TwoLinesWithCRLF_ReturnsTwoElements() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var lines = shaper.ShapeLines("Hello\r\nWorld"); + + // Assert + Assert.AreEqual(2, lines.Length); + Assert.AreEqual("Hello", lines[0].OriginalText); + Assert.AreEqual("World", lines[1].OriginalText); + } + + [TestMethod] + public void ShapeLines_EmptyLine_PreservesEmptyLine() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var lines = shaper.ShapeLines("Hello\n\nWorld"); + + // Assert + Assert.AreEqual(3, lines.Length); + Assert.AreEqual("Hello", lines[0].OriginalText); + Assert.AreEqual("", lines[1].OriginalText); + Assert.AreEqual("World", lines[2].OriginalText); + } + + [TestMethod] + public void MeasureLines_SingleLine_MatchesSingleMeasurement() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var metrics = shaper.MeasureLines("Hello", 12); + float singleWidth = shaper.MeasureTextInPoints("Hello", 12); + + // Assert + Assert.AreEqual(1, metrics.LineCount); + Assert.AreEqual(singleWidth, metrics.Width, 0.01f); + } + + [TestMethod] + public void MeasureLines_TwoLines_WidthIsMaxOfBoth() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var metrics = shaper.MeasureLines("Hi\nHello", 12); + float hiWidth = shaper.MeasureTextInPoints("Hi", 12); + float helloWidth = shaper.MeasureTextInPoints("Hello", 12); + + // Assert + Assert.AreEqual(2, metrics.LineCount); + Assert.AreEqual(Math.Max(hiWidth, helloWidth), metrics.Width, 0.01f); + } + + [TestMethod] + public void MeasureLines_TwoLines_HeightIsDoubleLineHeight() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var metrics = shaper.MeasureLines("Hello\nWorld", 12); + float lineHeight = shaper.GetLineHeightInPoints(12); + + // Assert + Assert.AreEqual(2, metrics.LineCount); + Assert.AreEqual(2 * lineHeight, metrics.Height, 0.01f); + } + + #endregion + + #region Height Calculation Tests + + [TestMethod] + public void GetLineHeightInPoints_ReturnsPositiveValue() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + float lineHeight = shaper.GetLineHeightInPoints(12); + + // Assert + Assert.IsTrue(lineHeight > 0, "Line height should be positive"); + Assert.IsTrue(lineHeight > 10, "Line height should be reasonable for 12pt"); + Assert.IsTrue(lineHeight < 30, "Line height should be reasonable for 12pt"); + } + + [TestMethod] + public void GetFontHeightInPoints_ReturnsPositiveValue() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + float fontHeight = shaper.GetFontHeightInPoints(12); + + // Assert + Assert.IsTrue(fontHeight > 0, "Font height should be positive"); + Assert.IsTrue(fontHeight > 10, "Font height should be reasonable for 12pt"); + Assert.IsTrue(fontHeight < 20, "Font height should be reasonable for 12pt"); + } + + [TestMethod] + public void GetLineHeight_IsGreaterThanFontHeight() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + float lineHeight = shaper.GetLineHeightInPoints(12); + float fontHeight = shaper.GetFontHeightInPoints(12); + + // Assert + Assert.IsTrue(lineHeight >= fontHeight, + "Line height (with line gap) should be >= font height"); + } + + [TestMethod] + public void GetLineHeight_ScalesWithFontSize() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + float height12 = shaper.GetLineHeightInPoints(12); + float height24 = shaper.GetLineHeightInPoints(24); + + // Assert + Assert.AreEqual(2.0f, height24 / height12, 0.01f, + "Line height should scale linearly with font size"); + } + + #endregion + + #region ShapedText Properties Tests + + [TestMethod] + public void ShapedText_GetWidthInPoints_MatchesMeasureText() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("Hello"); + float width1 = shaped.GetWidthInPoints(12); + float width2 = shaper.MeasureTextInPoints("Hello", 12); + + // Assert + Assert.AreEqual(width1, width2, 0.01f, "Both methods should return same width"); + } + + [TestMethod] + public void ShapedText_GetWidthInPixels_MatchesMeasureText() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var shaped = shaper.Shape("Hello"); + float width1 = shaped.GetWidthInPixels(12, 96); + float width2 = shaper.MeasureTextInPixels("Hello", 12, 96); + + // Assert + Assert.AreEqual(width1, width2, 0.01f, "Both methods should return same width"); + } + + #endregion + + #region Edge Cases + + [TestMethod] + public void Shape_OnlySpaces_ReturnsGlyphs() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape(" "); + + // Assert + Assert.AreEqual(3, shaped.Glyphs.Length); + Assert.IsTrue(shaped.TotalAdvanceWidth > 0, "Spaces should have width"); + } + + [TestMethod] + public void Shape_SpecialCharacters_HandlesGracefully() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("@#$%"); + + // Assert + Assert.AreEqual(4, shaped.Glyphs.Length); + Assert.IsTrue(shaped.TotalAdvanceWidth > 0); + } + + [TestMethod] + public void Shape_Numbers_ReturnsCorrectGlyphs() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var shaped = shaper.Shape("12345"); + + // Assert + Assert.AreEqual(5, shaped.Glyphs.Length); + Assert.IsTrue(shaped.TotalAdvanceWidth > 0); + } + + #endregion + + #region Shaping with ligatures + [TestMethod] + public void Shape_FiLigature_CombinesTwoGlyphs() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var withLigatures = shaper.Shape("fi", ShapingOptions.Default); + var withoutLigatures = shaper.Shape("fi", ShapingOptions.None); + + // Assert + Assert.IsTrue(withLigatures.Glyphs.Length < withoutLigatures.Glyphs.Length, + "Ligatures should combine glyphs (fi → 1 glyph instead of 2)"); + } + + [TestMethod] + public void Shape_Office_HasFfiLigature() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.Shape("office"); + + // Assert - "ffi" should be one ligature glyph with CharCount=3 + bool hasFfiLigature = result.Glyphs.Any(g => g.CharCount == 3); + Assert.IsTrue(hasFfiLigature, "Should find ffi ligature in 'office'"); + } + + [TestMethod] + public void Shape_Ligature_PreservesClusterIndex() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.Shape("afi"); + + // Assert + // Glyph[0]: 'a' at cluster 0 + // Glyph[1]: 'fi' ligature at cluster 1, represents 2 chars + Assert.AreEqual(0, result.Glyphs[0].ClusterIndex); + Assert.AreEqual(1, result.Glyphs[1].ClusterIndex); + Assert.AreEqual(2, result.Glyphs[1].CharCount); + } + #endregion + + [TestMethod] + public void Shape_DecomposedUnicode_PositionsAccent() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + // U+0065 = 'e', U+0301 = combining acute accent + var decomposed = shaper.Shape("e\u0301"); // e + ´ + + // Assert + Assert.AreEqual(2, decomposed.Glyphs.Length, "Should have 2 glyphs (base + mark)"); + + var baseGlyph = decomposed.Glyphs[0]; + var markGlyph = decomposed.Glyphs[1]; + + // Base glyph should have normal advance + Assert.IsTrue(baseGlyph.XAdvance > 0, "Base should advance"); + + // Mark should be positioned (XOffset/YOffset set) + // and should not advance (it's positioned over base) + Assert.AreEqual(0, markGlyph.XAdvance, "Mark should not advance"); + + // Mark should have positioning offsets + // (exact values depend on font, but should be non-zero for proper positioning) + Console.WriteLine($"Mark positioned at: XOffset={markGlyph.XOffset}, YOffset={markGlyph.YOffset}"); + } + + [TestMethod] + public void Shape_PrecomposedVsDecomposed_SimilarWidth() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Roboto", FontSubFamily.Regular); + + // Act + var precomposed = shaper.Shape("\u00e9"); // é (single codepoint) + var decomposed = shaper.Shape("e\u0301"); // e + combining acute + + // Assert - Both should have similar total width + // (within 10% tolerance for font design differences) + float preWidth = precomposed.TotalAdvanceWidth; + float decWidth = decomposed.TotalAdvanceWidth; + + float difference = Math.Abs(preWidth - decWidth); + float tolerance = preWidth * 0.1f; + + Assert.IsTrue(difference < tolerance, + $"Precomposed width ({preWidth}) and decomposed width ({decWidth}) " + + $"should be similar (diff: {difference}, tolerance: {tolerance})"); + } + + [TestMethod] + public void Shape_SourceSans3_SingleMark_PositionsCorrectly() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("SourceSans3"); + + // Act - Single combining mark + var result = shaper.Shape("e\u0301"); // e + combining acute (é) + + // Assert + Assert.AreEqual(2, result.Glyphs.Length, "Should have base + mark"); + + var baseGlyph = result.Glyphs[0]; + var markGlyph = result.Glyphs[1]; + + // Base should advance normally + Assert.IsTrue(baseGlyph.XAdvance > 0, "Base glyph should advance"); + + // Mark should NOT advance (positioned over base) + Assert.AreEqual(0, markGlyph.XAdvance, + "Mark should not advance (XAdvance=0)"); + + // Mark should be positioned (XOffset OR YOffset set) + // Note: YOffset can be 0 if mark is horizontally centered + Assert.IsTrue(markGlyph.XOffset != 0 || markGlyph.YOffset != 0, + $"Mark should have positioning (XOffset={markGlyph.XOffset}, YOffset={markGlyph.YOffset})"); + } + + [TestMethod] + public void Shape_Cafe_HandlesDecomposed() + { + var tEngine = + new Lazy(() => new OpenTypeFontEngine(cfg => + { + foreach (var folder in FontFolders) + cfg.FontDirectories.Add(folder); + cfg.SearchSystemDirectories = false; + })).Value; + + // Arrange + var shaper = tEngine.GetTextShaper("SourceSans3"); + + // Act - "café" with decomposed é + var result = shaper.Shape("cafe\u0301"); + + // Assert + Assert.AreEqual(5, result.Glyphs.Length, "c-a-f-e-´"); + + // Last glyph (accent) should not advance + Assert.AreEqual(0, result.Glyphs[4].XAdvance, "Accent should not advance"); + + // Should have positioning + Assert.IsTrue( + result.Glyphs[4].XOffset != 0 || result.Glyphs[4].YOffset != 0, + "Accent should be positioned"); + } + + [TestMethod] + public void Shape_Cafe_HandlesDecomposedSpecified() + { + // Arrange + var shaper = TestFolderEngine.GetTextShaper("Source Sans 3"); + + // Act - "café" with decomposed é + var result = shaper.Shape("cafe\u0301"); + + // Assert + Assert.AreEqual(5, result.Glyphs.Length, "c-a-f-e-´"); + + // Last glyph (accent) should not advance + Assert.AreEqual(0, result.Glyphs[4].XAdvance, "Accent should not advance"); + + // Should have positioning + Assert.IsTrue( + result.Glyphs[4].XOffset != 0 || result.Glyphs[4].YOffset != 0, + "Accent should be positioned"); + } + + [TestMethod] + public void Debug_OpenSans_MarkFeature() + { + var font = TestFolderEngine.LoadFont("OpenSans", FontSubFamily.Regular); + + foreach (var featureRecord in font.GposTable.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "mark") + { + Debug.WriteLine($"OpenSans 'mark' feature:"); + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < font.GposTable.LookupList.Lookups.Count) + { + var lookup = font.GposTable.LookupList.Lookups[lookupIndex]; + Debug.WriteLine($" Lookup Type: {lookup.LookupType}"); + Debug.WriteLine($" SubTables: {lookup.SubTables?.Count ?? 0}"); + + if (lookup.SubTables != null) + { + foreach (var st in lookup.SubTables) + { + Debug.WriteLine($" SubTable type: {st?.GetType().Name ?? "null"}"); + } + } + } + } + } + } + } + + [TestClass] + public class SingleAdjustmentDiscoveryTests + { + private static readonly string[] FontFolders = { @"C:\Windows\Fonts", @"C:\Fonts" }; + + [TestMethod] + public void Discovery_CheckFontsForSingleAdjustment() + { + var fontNames = new[] + { + ("Verdana", FontSubFamily.Regular), + ("Arial", FontSubFamily.Regular), + ("Helvetica", FontSubFamily.Regular) + }; + + foreach (var (fontName, subFamily) in fontNames) + { + try + { + var font = OpenTypeFonts.LoadFont(fontName, subFamily); + + if (font.GposTable == null) + { + Debug.WriteLine($"{fontName}: No GPOS table"); + continue; + } + + int singleAdjustmentCount = 0; + + foreach (var lookup in font.GposTable.LookupList.Lookups) + { + if (lookup.LookupType == 1) // Single Adjustment + { + foreach (var subtable in lookup.SubTables) + { + if (subtable is SinglePosSubTableFormat1 format1) + { + singleAdjustmentCount++; + var value = format1.Value; + Debug.WriteLine($"{fontName}: Format 1"); + Debug.WriteLine($" Coverage: {format1.Coverage?.GetCoveredGlyphs().Length ?? 0} glyphs"); + Debug.WriteLine($" XPlacement: {value?.XPlacement ?? 0}"); + Debug.WriteLine($" YPlacement: {value?.YPlacement ?? 0}"); + Debug.WriteLine($" XAdvance: {value?.XAdvance ?? 0}"); + Debug.WriteLine($" YAdvance: {value?.YAdvance ?? 0}"); + + // Show first few covered glyphs + var coveredGlyphs = format1.Coverage?.GetCoveredGlyphs(); + if (coveredGlyphs != null && coveredGlyphs.Length > 0) + { + Debug.Write($" First glyphs: "); + for (int i = 0; i < System.Math.Min(5, coveredGlyphs.Length); i++) + { + Debug.Write($"{coveredGlyphs[i]} "); + } + Debug.WriteLine(""); + } + } + else if (subtable is SinglePosSubTableFormat2 format2) + { + singleAdjustmentCount++; + Debug.WriteLine($"{fontName}: Format 2 - {format2.ValueCount} adjustments"); + Debug.WriteLine($" Coverage: {format2.Coverage?.GetCoveredGlyphs().Length ?? 0} glyphs"); + + // Show first few values + if (format2.Values != null && format2.Values.Length > 0) + { + Debug.WriteLine($" First value: XPlacement={format2.Values[0]?.XPlacement ?? 0}, YPlacement={format2.Values[0]?.YPlacement ?? 0}"); + } + } + } + } + } + + if (singleAdjustmentCount == 0) + { + Debug.WriteLine($"{fontName}: No Single Adjustment lookups found"); + } + } + catch (System.Exception ex) + { + Debug.WriteLine($"{fontName}: Error - {ex.Message}"); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/TextShaping/VerticalTextShapingTests.cs b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/VerticalTextShapingTests.cs new file mode 100644 index 0000000000..c2817363b0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/TextShaping/VerticalTextShapingTests.cs @@ -0,0 +1,368 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical text shaping tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tests; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Interfaces.Drawing.Text; + +namespace EPPlus.Fonts.OpenType.TextShaping +{ + [TestClass] + public class VerticalTextShapingTests : FontTestBase + { + public override TestContext TestContext { get; set; } + + [ClassInitialize] + public static void ClassInitialize(TestContext ctx) + { + FontDirectoriesTestHelper.ClassInitialize(ctx); + } + + #region ShapeVertical tests + + [TestMethod] + public void ShapeVertical_CjkText_ReturnsOneGlyphPerCharacter() + { + // Arrange - BIZ UDGothic has vmtx and is a CJK font + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("日本語"); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.Glyphs.Length, "Expected one glyph per character"); + } + + [TestMethod] + public void ShapeVertical_CjkText_GlyphsHavePositiveYAdvance() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var result = shaper.ShapeVertical("日本語"); + + // Assert - all glyphs must have a positive YAdvance (sourced from vmtx) + foreach (var glyph in result.Glyphs) + { + Assert.IsTrue(glyph.YAdvance > 0, + $"Glyph {glyph.GlyphId} has YAdvance {glyph.YAdvance}, expected > 0"); + } + } + + [TestMethod] + public void ShapeVertical_CjkText_TotalAdvanceHeightIsPositive() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("テスト"); + + // Assert + Assert.IsTrue(result.TotalAdvanceHeight > 0, + $"TotalAdvanceHeight should be positive, was {result.TotalAdvanceHeight}"); + } + + [TestMethod] + public void ShapeVertical_EmptyString_ReturnsEmptyGlyphArray() + { + // Arrange + var font = OpenTypeFonts.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical(string.Empty); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Glyphs.Length); + Assert.AreEqual(string.Empty, result.OriginalText); + } + + [TestMethod] + public void ShapeVertical_ClusterIndexMatchesCharacterPosition() + { + // Arrange + var font = OpenTypeFonts.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + var text = "ABC"; + + // Act + var result = shaper.ShapeVertical(text); + + // Assert - ClusterIndex must map back to the correct character position + Assert.AreEqual(3, result.Glyphs.Length); + for (int i = 0; i < result.Glyphs.Length; i++) + { + Assert.AreEqual((ushort)i, result.Glyphs[i].ClusterIndex, + $"Glyph {i} has ClusterIndex {result.Glyphs[i].ClusterIndex}, expected {i}"); + } + } + + #endregion + + #region ShapeLightVertical tests + + [TestMethod] + public void ShapeLightVertical_CjkText_ReturnsOneEntryPerCharacter() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeLightVertical("日本語"); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.Length, "Expected one VerticalGlyphHeight per character"); + } + + [TestMethod] + public void ShapeLightVertical_CjkText_YAdvanceMatchesShapeVertical() + { + // Arrange - ShapeLightVertical should produce identical YAdvance values to ShapeVertical + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + var text = "東京"; + + // Act + var full = shaper.ShapeVertical(text); + var light = shaper.ShapeLightVertical(text); + + // Assert + Assert.AreEqual(full.Glyphs.Length, light.Length); + for (int i = 0; i < full.Glyphs.Length; i++) + { + Assert.AreEqual(full.Glyphs[i].YAdvance, light[i].YAdvance, + $"YAdvance mismatch at index {i}: ShapeVertical={full.Glyphs[i].YAdvance}, ShapeLightVertical={light[i].YAdvance}"); + } + } + + [TestMethod] + public void ShapeLightVertical_EmptyString_ReturnsEmptyArray() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine,font); + + // Act + var result = shaper.ShapeLightVertical(string.Empty); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Length); + } + + #endregion + + + #region Fallback tests (fonts without vmtx) + + [TestMethod] + public void ShapeVertical_FontWithoutVmtx_FallsBackToHmtxAdvanceWidth() + { + // Arrange - Calibri has no vmtx table, fallback to hmtx should kick in + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine,font); + Assert.IsNull(font.VmtxTable, "Roboto should not have a vmtx table"); + + // Act + var result = shaper.ShapeVertical("ABC"); + + // Assert - YAdvance should still be positive (sourced from hmtx advanceWidth) + Assert.AreEqual(3, result.Glyphs.Length); + foreach (var glyph in result.Glyphs) + { + Assert.IsTrue(glyph.YAdvance > 0, + $"Glyph {glyph.GlyphId} has YAdvance {glyph.YAdvance}, expected > 0 via hmtx fallback"); + Assert.AreEqual((short)0, glyph.TopSideBearing, + "TopSideBearing should be 0 when falling back to hmtx"); + } + } + + [TestMethod] + public void ShapeVertical_FontWithoutVmtx_YAdvanceMatchesHmtxAdvanceWidth() + { + // Arrange + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("A"); + + // Assert - YAdvance should equal hmtx advanceWidth for the same glyph + var glyphId = result.Glyphs[0].GlyphId; + var expectedAdvance = font.HmtxTable.GetAdvanceWidth(glyphId); + Assert.AreEqual(expectedAdvance, result.Glyphs[0].YAdvance, + "YAdvance via fallback should equal hmtx advanceWidth"); + } + + #endregion + + #region OriginalText and FontId tests + + [TestMethod] + public void ShapeVertical_OriginalTextIsPreserved() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + var text = "日本語テスト"; + + // Act + var result = shaper.ShapeVertical(text); + + // Assert + Assert.AreEqual(text, result.OriginalText); + } + + [TestMethod] + public void ShapeVertical_PrimaryFontGlyphs_HaveFontIdZero() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("日本語"); + + // Assert - all glyphs should be from primary font (FontId == 0) + foreach (var glyph in result.Glyphs) + { + Assert.AreEqual((byte)0, glyph.FontId, + $"Glyph {glyph.GlyphId} has FontId {glyph.FontId}, expected 0 for primary font"); + } + } + + #endregion + + #region Surrogate pair tests + + [TestMethod] + public void ShapeVertical_SurrogatePair_ProducesOneGlyphWithCharCountTwo() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine,font); + + // U+20B9F 𠺟 - a CJK unified ideograph extension B character (surrogate pair in UTF-16) + var text = "\uD842\uDF9F"; + Assert.AreEqual(2, text.Length, "Surrogate pair should be 2 UTF-16 code units"); + + // Act + var result = shaper.ShapeVertical(text); + + // Assert - surrogate pair should produce exactly one glyph + Assert.AreEqual(1, result.Glyphs.Length, + "A surrogate pair should produce exactly one glyph"); + Assert.AreEqual((byte)2, result.Glyphs[0].CharCount, + "CharCount should be 2 for a surrogate pair"); + Assert.AreEqual((ushort)0, result.Glyphs[0].ClusterIndex, + "ClusterIndex should point to the start of the surrogate pair"); + } + + [TestMethod] + public void ShapeLightVertical_SurrogatePair_ProducesOneEntryWithCharCountTwo() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + var text = "\uD842\uDF9F"; + + // Act + var result = shaper.ShapeLightVertical(text); + + // Assert + Assert.AreEqual(1, result.Length, + "A surrogate pair should produce exactly one VerticalGlyphHeight"); + Assert.AreEqual((byte)2, result[0].CharCount, + "CharCount should be 2 for a surrogate pair"); + } + + #endregion + + #region Centering tests + + [TestMethod] + public void ShapeVertical_CjkText_GlyphsHavePositiveAdvanceWidth() + { + // Arrange + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("日本語"); + + // Assert - AdvanceWidth is required for horizontal centering in vertical text columns + foreach (var glyph in result.Glyphs) + { + Assert.IsTrue(glyph.AdvanceWidth > 0, + $"Glyph {glyph.GlyphId} has AdvanceWidth {glyph.AdvanceWidth}, expected > 0"); + } + } + + [TestMethod] + public void ShapeVertical_AdvanceWidthMatchesHmtxAdvanceWidth() + { + // Arrange - AdvanceWidth on VerticalShapedGlyph must equal hmtx advanceWidth + // since centering calculations depend on this value being accurate + var font = TestFolderEngine.LoadFont("BIZ UDGothic"); + var shaper = new TextShaper(TestFolderEngine, font); + + // Act + var result = shaper.ShapeVertical("日本"); + + // Assert + foreach (var glyph in result.Glyphs) + { + var expectedAdvanceWidth = font.HmtxTable.GetAdvanceWidth(glyph.GlyphId); + Assert.AreEqual(expectedAdvanceWidth, glyph.AdvanceWidth, + $"Glyph {glyph.GlyphId}: AdvanceWidth {glyph.AdvanceWidth} " + + $"does not match hmtx advanceWidth {expectedAdvanceWidth}"); + } + } + + [TestMethod] + public void ShapeVertical_FontWithoutVmtx_AdvanceWidthMatchesHmtxAdvanceWidth() + { + // Arrange - Roboto has no vmtx table, both YAdvance and AdvanceWidth + // should fall back to hmtx and be equal to each other + var font = TestFolderEngine.LoadFont("Roboto"); + var shaper = new TextShaper(TestFolderEngine, font); + Assert.IsNull(font.VmtxTable, "Roboto should not have a vmtx table"); + + // Act + var result = shaper.ShapeVertical("ABC"); + + // Assert + foreach (var glyph in result.Glyphs) + { + var expectedAdvanceWidth = font.HmtxTable.GetAdvanceWidth(glyph.GlyphId); + Assert.AreEqual(expectedAdvanceWidth, glyph.AdvanceWidth, + $"Glyph {glyph.GlyphId}: AdvanceWidth {glyph.AdvanceWidth} " + + $"does not match hmtx advanceWidth {expectedAdvanceWidth}"); + Assert.AreEqual(glyph.YAdvance, glyph.AdvanceWidth, + $"Glyph {glyph.GlyphId}: YAdvance and AdvanceWidth should be equal " + + $"when falling back to hmtx (YAdvance={glyph.YAdvance}, AdvanceWidth={glyph.AdvanceWidth})"); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType.Tests/Validation/CmapTableValidationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Validation/CmapTableValidationTests.cs new file mode 100644 index 0000000000..6ab5269792 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Validation/CmapTableValidationTests.cs @@ -0,0 +1,33 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Validation +{ + [TestClass] + public class CmapTableValidationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [ClassInitialize] + public static void Initialize(TestContext testContext) + { + FontDirectoriesTestHelper.ClassInitialize(testContext); + } + + [TestMethod] + public void CmapTableValidation_Test() + { + var font = OpenTypeFonts.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new CmapTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.CmapTable, context); + Assert.IsTrue(result.IsValid, "Cmap validation failed for a known good font."); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Validation/CoreTableValidationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Validation/CoreTableValidationTests.cs new file mode 100644 index 0000000000..b5445a5133 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Validation/CoreTableValidationTests.cs @@ -0,0 +1,83 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Hhea; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using EPPlus.Fonts.OpenType.Tables.Name; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.Tables.Post; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Validation +{ + [TestClass] + public class CoreTableValidationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void HeadTable_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new HeadTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.HeadTable, context); + Assert.IsTrue(result.IsValid); + } + + + [TestMethod] + public void MaxpTable_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new MaxpTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.MaxpTable, context); + Assert.IsTrue(result.IsValid, "MaxpTable validation failed for a known good font."); + } + + [TestMethod] + public void HheaTable_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new HheaTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.HheaTable, context); + Assert.IsTrue(result.IsValid, "Hhea validation failed for a known good font."); + } + + [TestMethod] + public void NameTable_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new NameTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.NameTable, context); + Assert.IsTrue(result.IsValid, "Name validation failed for a known good font."); + } + + [TestMethod] + public void Os2Table_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new Os2TableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.Os2Table, context); + Assert.IsTrue(result.IsValid, "Os/2 validation failed for a known good font."); + } + + [TestMethod] + public void PostTable_Validation_ShouldPass() + { + var font = TestFolderEngine.LoadFont("Roboto", FontSubFamily.Regular); + var validator = new PostTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.PostTable, context); + Assert.IsTrue(result.IsValid, "Post validation failed for a known good font."); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Validation/EntireFontValidationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Validation/EntireFontValidationTests.cs new file mode 100644 index 0000000000..eddcc0f00c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Validation/EntireFontValidationTests.cs @@ -0,0 +1,19 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tests.Helpers; + +namespace EPPlus.Fonts.OpenType.Tests.Validation +{ + [TestClass] + public class EntireFontValidationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void ValidateEntireFont() + { + var font = TestFolderEngine.LoadFont("Roboto"); + var report = font.ValidateFont(FontValidationSeverity.Error); + Assert.IsTrue(report.IsValid); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Validation/GlyphTableValidationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Validation/GlyphTableValidationTests.cs new file mode 100644 index 0000000000..06d4ea8794 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Validation/GlyphTableValidationTests.cs @@ -0,0 +1,53 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tests.Helpers; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tests.Validation +{ + [TestClass] + public class GlyphTableValidationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + public void LocaTableValidation_Test() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + var validator = new LocaTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.LocaTable, context); + Assert.IsTrue(result.IsValid, "Loca validation failed for a known good font."); + } + + [TestMethod] + public void HmtxTableValidation_Test() + { + var font = OpenTypeFonts.LoadFont("Roboto"); + var validator = new HmtxTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.HmtxTable, context); + Assert.IsTrue(result.IsValid, "Hmtx validation failed for a known good font."); + } + + [TestMethod] + [DataRow("Roboto", FontSubFamily.Regular)] + [DataRow("Roboto", FontSubFamily.Italic)] + [DataRow("EB Garamond", FontSubFamily.Regular)] + [DataRow("Mulish", FontSubFamily.Regular)] + public void GlyfTableValidation_Test(string fontName, FontSubFamily subFamily) + { + var font = OpenTypeFonts.LoadFont(fontName, subFamily); + var validator = new GlyfTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.GlyfTable, context); + Assert.IsTrue(result.IsValid, $"Glyf validation failed for a known good font: {fontName} {subFamily}"); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/Validation/GsubTableValidationTests.cs b/src/EPPlus.Fonts.OpenType.Tests/Validation/GsubTableValidationTests.cs new file mode 100644 index 0000000000..4c37fee533 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/Validation/GsubTableValidationTests.cs @@ -0,0 +1,26 @@ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tests.Helpers; + +namespace EPPlus.Fonts.OpenType.Tests.Validation +{ + [TestClass] + public class GsubTableValidationTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + [TestMethod] + [DataRow("Roboto")] + [DataRow("OpenSans")] + [DataRow("SourceSans3")] + [DataRow("NotoEmoji")] + public void GsubTableValidation_Test(string fontName) + { + var font = OpenTypeFonts.LoadFont(fontName); + var validator = new GsubTableValidator(); + var context = new FontValidationContext(font); + var result = validator.Validate(font.GsubTable, context); + Assert.IsTrue(result.IsValid, $"Gsub validation failed for a known good font. {fontName}"); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType.Tests/VariableFonts/VariableFontMatchingTests .cs b/src/EPPlus.Fonts.OpenType.Tests/VariableFonts/VariableFontMatchingTests .cs new file mode 100644 index 0000000000..dfcad40886 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType.Tests/VariableFonts/VariableFontMatchingTests .cs @@ -0,0 +1,132 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 06/25/2026 EPPlus Software AB Variable font matching tests + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tests.VariableFonts +{ + /// + /// Verifies that the font scanner treats variable fonts as capable of delivering only + /// their default named instance. A variable font must not masquerade as an exact match + /// for a non-default subfamily. + /// + /// Regression context: a developer had Archivo Narrow installed as a wght-axis variable + /// web font. The scanner returned that file for a Bold request, the font library then read + /// the default (Regular) instance, and the developer wrote asserts against those Regular + /// values. On machines without the variable font installed, resolution fell back to the + /// embedded static Archivo Narrow Bold and the asserts failed — a non-deterministic, + /// machine-dependent test failure. + /// + /// These tests are deliberately written against FontScannerV2 directly (not through an + /// engine) so they exercise exactly the matching logic that changed, with no dependency on + /// system-installed fonts and no interference from the Archivo Narrow special-case in + /// DefaultFontResolver. + /// + [TestClass] + public class VariableFontMatchingTests : FontTestBase + { + public override TestContext? TestContext { get; set; } + + // Variable (wght-axis) build of Archivo Narrow. Its default instance is Regular (wght 400). + private const string VariableFontFamily = "Archivo Narrow"; + private const string VariableFontFileName = "ArchivoNarrow-VariableFont_wght.ttf"; + + /// + /// The isolated directory containing only the variable font. Pointing the scanner here + /// (with system directories disabled) guarantees the variable face is the only candidate, + /// which makes the disqualification observable as a null result. + /// + private static List VariableFontDirectories + { + get { return new List { Path.Combine(FontFolder, "VariableFonts") }; } + } + + private static string VariableFontPath + { + get { return Path.Combine(FontFolder, "VariableFonts", VariableFontFileName); } + } + + [TestMethod] + public void ScanSingleFace_VariableFont_SetsIsVariable() + { + // The fvar table must be detected purely from the table directory. + var face = FontScannerV2.GetFace(VariableFontPath); + + Assert.IsNotNull(face, "Expected the variable font to be scanned."); + Assert.IsTrue(face.IsVariable, + "A font containing an 'fvar' table must be flagged as variable."); + } + + [TestMethod] + public void FindBestMatch_VariableFont_DefaultStyle_IsExactMatch() + { + // The default instance of this variable font IS Regular, so a Regular request is a + // legitimate exact match. This guards against over-penalising variable fonts: they + // must still satisfy a request for their default subfamily. + var match = FontScannerV2.FindBestMatch( + VariableFontDirectories, + VariableFontFamily, + FontSubFamily.Regular, + searchSystemDirectories: false); + + Assert.IsNotNull(match, + "A variable font must still match a request for its default (Regular) subfamily."); + Assert.IsTrue(match.IsVariable, "The matched face is expected to be variable."); + Assert.AreEqual(FontSubFamily.Regular, match.Subfamily); + Assert.IsTrue(match.IsExactMatch, + "A variable font matching its default subfamily must be reported as an exact match."); + } + + [TestMethod] + public void FindBestMatch_VariableFont_NonDefaultStyle_IsDisqualified() + { + // Bold is NOT the default instance. Without variation interpolation the file cannot + // deliver Bold, so the variable face must be disqualified. With no other candidate in + // the isolated directory, the scanner returns null — and crucially never returns the + // Regular face flagged as an exact Bold match (the original bug). + var match = FontScannerV2.FindBestMatch( + VariableFontDirectories, + VariableFontFamily, + FontSubFamily.Bold, + searchSystemDirectories: false); + + Assert.IsNull(match, + "A variable font whose default instance is not Bold must not be returned as a " + + "match for a Bold request when it is the only candidate."); + } + + [TestMethod] + public void FindBestMatch_VariableFont_NonDefaultStyle_IsNotExactMatch() + { + // Belt-and-braces companion to the disqualification test, phrased as the property we + // actually care about: even if some future change let a variable face survive as a + // low-scoring candidate for a non-default style, it must never be flagged exact. + var match = FontScannerV2.FindBestMatch( + VariableFontDirectories, + VariableFontFamily, + FontSubFamily.BoldItalic, + searchSystemDirectories: false); + + // Current behaviour: disqualified → null. If that ever changes, the match must at + // least not be exact. + if (match != null) + { + Assert.IsFalse(match.IsExactMatch, + "A variable font must never be an exact match for a non-default subfamily."); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/.editorconfig b/src/EPPlus.Fonts.OpenType/.editorconfig new file mode 100644 index 0000000000..d01948aa3c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/.editorconfig @@ -0,0 +1,244 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Code Actions #### + +# Type members +dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_prefer_system_hash_code = true +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_anonymous_function = true +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_prefer_system_threading_lock = true +csharp_style_namespace_declarations = block_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_primary_constructors = true +csharp_style_prefer_top_level_statements = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/src/EPPlus.Fonts.OpenType/AssemblyInfo.cs b/src/EPPlus.Fonts.OpenType/AssemblyInfo.cs new file mode 100644 index 0000000000..4acf72f2f1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.CompilerServices; +using System.Security; + +[assembly: AllowPartiallyTrustedCallers] +[assembly: InternalsVisibleTo("EPPlus.Fonts.OpenType.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e919e6cd771194b1b1ade084355488193b5e639a2ffed859ad956760b1489eab4e21c1949bf4e947cac2a430f232d15484062cb8314340b7db4d67b49b2e4c270bc02c457e06ee7dd4e6ecf09277543e696525f8d31d2228a1fe205aaa824573d08214c12d9ed7c73b5658d98131efd0ab69f9847c22f20b712f479f2d0032d6")] diff --git a/src/EPPlus.Fonts.OpenType/BoundingRectangle.cs b/src/EPPlus.Fonts.OpenType/BoundingRectangle.cs new file mode 100644 index 0000000000..b67854bb92 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/BoundingRectangle.cs @@ -0,0 +1,49 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType +{ + [DebuggerDisplay("x: ({Xmin} to {Xmax}), y: ({Ymin} to {Ymax})")] + public struct BoundingRectangle + { + internal BoundingRectangle(short xMin, short yMin, short xMax, short yMax) + { + Xmin = xMin; + Ymin = yMin; + Xmax = xMax; + Ymax = yMax; + } + /// + /// Minimum x coordinate across all glyph bounding boxes. + /// + public short Xmin { get; set; } + + /// + /// Minimum y coordinate across all glyph bounding boxes. + /// + public short Ymin { get; set; } + + /// + /// Maximum x coordinate across all glyph bounding boxes. + /// + public short Xmax { get; set; } + + /// + /// Maximum y coordinate across all glyph bounding boxes. + /// + public short Ymax { get; set; } + + public static BoundingRectangle Empty => new BoundingRectangle(-1, -1, -1, -1); + } +} diff --git a/src/EPPlus.Fonts.OpenType/CustomFontProvider.cs b/src/EPPlus.Fonts.OpenType/CustomFontProvider.cs new file mode 100644 index 0000000000..fc74bcacdc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/CustomFontProvider.cs @@ -0,0 +1,93 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Custom font provider where user defines their own fallback chain. + /// Does NOT use embedded Noto Emoji - user must add fallbacks manually. + /// + public class CustomFontProvider : IFontProvider + { + private readonly OpenTypeFont _primaryFont; + private readonly List _fallbackFonts; + + public OpenTypeFont PrimaryFont + { + get { return _primaryFont; } + } + + /// + /// Creates a custom font provider without any fallbacks. + /// + /// The user's primary font + public CustomFontProvider(OpenTypeFont primaryFont) + { + if (primaryFont == null) + throw new ArgumentNullException("primaryFont"); + + _primaryFont = primaryFont; + _fallbackFonts = new List(); + } + + /// + /// Adds a fallback font to the chain. + /// Fonts are searched in the order they are added. + /// + /// Fallback font to add + public void AddFallback(OpenTypeFont font) + { + if (font == null) + throw new ArgumentNullException("font"); + + _fallbackFonts.Add(font); + } + + public bool TryGetGlyphFont(uint codePoint, out OpenTypeFont font, out ushort glyphId) + { + // Try primary font first + if (_primaryFont.CmapTable.TryGetGlyphId(codePoint, out glyphId)) + { + font = _primaryFont; + return true; + } + + // Try fallback fonts in order + foreach (var fallbackFont in _fallbackFonts) + { + if (fallbackFont.CmapTable.TryGetGlyphId(codePoint, out glyphId)) + { + font = fallbackFont; + return true; + } + } + + // Not found - return primary with .notdef + font = _primaryFont; + glyphId = 0; + return false; + } + + public IEnumerable GetAllFonts() + { + yield return _primaryFont; + + foreach (var fallback in _fallbackFonts) + { + yield return fallback; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/DefaultFontProvider.cs b/src/EPPlus.Fonts.OpenType/DefaultFontProvider.cs new file mode 100644 index 0000000000..3640404e4c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/DefaultFontProvider.cs @@ -0,0 +1,313 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/24/2026 EPPlus Software AB Dynamic fallback chain with lazy loading + 05/20/2026 EPPlus Software AB Script-classified fallback via engine reference + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontResolver; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Default font provider with script-classified glyph fallback. + /// + /// When a code point is missing from the primary font, the provider routes the lookup + /// based on the code point's Unicode script: + /// * Emoji → embedded Noto Emoji (bundled with EPPlus) + /// * Math → embedded Noto Math (bundled with EPPlus) + /// * Other → per-script fallback chain configured on the engine (best-effort, + /// resolves named fonts via the engine — works only when the named fonts + /// are installed) + /// + /// Per-script chains and their fonts are lazy-loaded the first time a code point in + /// that script is encountered, then cached for the lifetime of this provider. + /// + public class DefaultFontProvider : IFontProvider + { + private readonly OpenTypeFontEngine _engine; + private readonly OpenTypeFont _primaryFont; + + // Embedded fallbacks, lazy-loaded on first use. + private readonly LazyFallbackFont _notoEmoji; + private readonly LazyFallbackFont _notoMath; + + // Per-script named fallbacks, resolved via the engine on first use of each script. + // Inner list is the resolved chain of fonts for that script; entries that fail to + // resolve are omitted (so the list may be shorter than the configured chain). + private readonly Dictionary> _resolvedScriptChains + = new Dictionary>(); + + // Tracks which fallback fonts have actually been used (returned a glyph for some + // code point). Used by GetAllFonts to expose only the fonts that mattered, which + // matters for subsetting and PDF embedding. + private readonly HashSet _usedFallbacks = new HashSet(); + + private readonly object _lock = new object(); + + /// + public OpenTypeFont PrimaryFont + { + get { return _primaryFont; } + } + + /// + /// Creates a font provider that uses the given engine to resolve per-script fallback + /// fonts on demand. Both arguments are required. + /// + /// The engine to use for resolving named fallback fonts. + /// The primary font for text in the user's chosen typeface. + public DefaultFontProvider(OpenTypeFontEngine engine, OpenTypeFont primaryFont) + { + if (engine == null) + throw new ArgumentNullException("engine"); + if (primaryFont == null) + throw new ArgumentNullException("primaryFont"); + + _engine = engine; + _primaryFont = primaryFont; + _notoEmoji = new LazyFallbackFont(EmbeddedFonts.LoadNotoEmoji); + _notoMath = new LazyFallbackFont(EmbeddedFonts.LoadNotoMath); + } + + /// + public bool TryGetGlyphFont(uint codePoint, out OpenTypeFont font, out ushort glyphId) + { + // 1. Primary font wins whenever it has the glyph. + if (_primaryFont.CmapTable.TryGetGlyphId(codePoint, out glyphId)) + { + font = _primaryFont; + return true; + } + + // 2. Classify the code point and route to the appropriate fallback. + var script = UnicodeScriptClassifier.OfCodePoint(codePoint); + + switch (script) + { + case UnicodeScript.Emoji: + if (TryGlyphInLazyFallback(_notoEmoji, codePoint, out font, out glyphId)) + return true; + break; + + case UnicodeScript.Math: + if (TryGlyphInLazyFallback(_notoMath, codePoint, out font, out glyphId)) + return true; + break; + + case UnicodeScript.Unknown: + // No script classification — no useful fallback to route to. + break; + + default: + if (TryGlyphInScriptChain(script, codePoint, out font, out glyphId)) + return true; + break; + } + + // 3. Nothing found — return primary with .notdef. + font = _primaryFont; + glyphId = 0; + return false; + } + + /// + public IEnumerable GetAllFonts() + { + yield return _primaryFont; + + // Only return fallback fonts that have actually been used. Subsetting and PDF + // embedding only need fonts whose glyphs the shaper actually placed. + lock (_lock) + { + foreach (var f in _usedFallbacks) + { + yield return f; + } + } + } + + // ----------------------------------------------------------------------------------------- + // Internal helpers + // ----------------------------------------------------------------------------------------- + + /// + /// Resolves a shaper for a different font through this provider's engine. Used by the + /// layout engine to shape rich-text fragments that switch typeface, so the lookup goes + /// through the same engine that created this provider — not the global OpenTypeFonts + /// singleton. Kept internal: the engine dependency stays encapsulated here rather than + /// leaking onto IFontProvider. + /// + internal ITextShaper GetShaperForFont(IFontFormatBase font) + { + return _engine.GetShaperForFont(font); + } + + internal ITextShaper GetShaperForFont(MeasurementFont font) + { + return _engine.GetShaperForFont(font); + } + + /// + /// Tries to find the glyph in a lazy-loaded embedded fallback font (Noto Emoji / Math). + /// + /// + private bool TryGlyphInLazyFallback( + LazyFallbackFont lazy, + uint codePoint, + out OpenTypeFont font, + out ushort glyphId) + { + var fallbackFont = lazy.Font; // triggers load on first use (thread-safe inside) + if (fallbackFont.CmapTable.TryGetGlyphId(codePoint, out glyphId)) + { + font = fallbackFont; + MarkUsed(fallbackFont); + return true; + } + + font = null; + glyphId = 0; + return false; + } + + /// + /// Tries to find the glyph by walking the per-script fallback chain configured on + /// the engine. Resolves the chain lazily on first use of each script. + /// + private bool TryGlyphInScriptChain( + UnicodeScript script, + uint codePoint, + out OpenTypeFont font, + out ushort glyphId) + { + var chain = GetOrResolveScriptChain(script); + + foreach (var candidate in chain) + { + if (candidate.CmapTable.TryGetGlyphId(codePoint, out glyphId)) + { + font = candidate; + MarkUsed(candidate); + return true; + } + } + + font = null; + glyphId = 0; + return false; + } + + /// + /// Returns the resolved chain of fonts for a script. The first time a script is + /// queried, the configured chain of font names is read from the engine's configuration + /// and each name is resolved via the engine. Names that fail to resolve are omitted. + /// + private List GetOrResolveScriptChain(UnicodeScript script) + { + lock (_lock) + { + List resolved; + if (_resolvedScriptChains.TryGetValue(script, out resolved)) + return resolved; + + resolved = ResolveScriptChain(script); + _resolvedScriptChains[script] = resolved; + return resolved; + } + } + + /// + /// Reads the configured chain for a script from the engine and loads each named font. + /// + private List ResolveScriptChain(UnicodeScript script) + { + var result = new List(); + + var chainNames = _engine.GetScriptFallback(script); + if (chainNames == null || chainNames.Length == 0) + return result; + + foreach (var fontName in chainNames) + { + if (string.IsNullOrEmpty(fontName)) + continue; + + // Only accept exact matches — falling back from "Microsoft YaHei" to Archivo + // Narrow defeats the purpose of script fallback. We rely on the engine's + // availability check rather than blindly loading. + var availability = _engine.GetFontAvailability(fontName, FontSubFamily.Regular); + if (availability != FontAvailability.Exact) + continue; + + try + { + var font = _engine.LoadFont(fontName, FontSubFamily.Regular); + if (font != null) + result.Add(font); + } + catch + { + // If a named fallback fails to load for any reason, skip it silently. + // The chain is best-effort — we never want a fallback font's loading + // error to break primary text rendering. + } + } + + return result; + } + + private void MarkUsed(OpenTypeFont font) + { + lock (_lock) + { + _usedFallbacks.Add(font); + } + } + + /// + /// Wraps an embedded font loader with lazy, thread-safe initialization. + /// + private class LazyFallbackFont + { + private readonly Func _loader; + private OpenTypeFont _font; + private readonly object _lock = new object(); + + internal LazyFallbackFont(Func loader) + { + _loader = loader; + } + + internal OpenTypeFont Font + { + get + { + if (_font == null) + { + lock (_lock) + { + if (_font == null) + { + _font = _loader(); + } + } + } + return _font; + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.csproj b/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.csproj new file mode 100644 index 0000000000..b926afb9fa --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.csproj @@ -0,0 +1,101 @@ + + + net9.0;net8.0;netstandard2.1;netstandard2.0;net462 + 1.0.0.0 + 1.0.0.0 + 1.0.0 + true + license.md + git + + EPPlus.Fonts.OpenType + readme.md + EPPlusLogo.png + latest + True + EPPlus.Fonts.OpenType.snk + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + True + \ + + + True + + + + True + + + + + + + + + + diff --git a/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.snk b/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.snk new file mode 100644 index 0000000000..fd5c1be8b9 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/EPPlus.Fonts.OpenType.snk differ diff --git a/src/EPPlus.Fonts.OpenType/EPPlusLogo.png b/src/EPPlus.Fonts.OpenType/EPPlusLogo.png new file mode 100644 index 0000000000..ad7b01cd1d Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/EPPlusLogo.png differ diff --git a/src/EPPlus.Fonts.OpenType/EmbeddedFonts.cs b/src/EPPlus.Fonts.OpenType/EmbeddedFonts.cs new file mode 100644 index 0000000000..7c6198b17e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/EmbeddedFonts.cs @@ -0,0 +1,129 @@ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Loads embedded fallback fonts. + /// Internal - not exposed to users. + /// + internal static class EmbeddedFonts + { + private static readonly Dictionary _cache = + new Dictionary(); + + private static readonly object _lock = new object(); + + /// + /// Loads Noto Emoji Regular (embedded resource). + /// Cached after first load. + /// + internal static OpenTypeFont LoadNotoEmoji() + { + return LoadCached("NotoEmoji-Regular.ttf"); + } + + internal static OpenTypeFont LoadNotoMath() + { + return LoadCached("NotoSansMath-Regular.ttf"); + } + + internal static OpenTypeFont LoadArchivoNarrow(FontSubFamily subFamily) + { + if (subFamily == FontSubFamily.Italic) + { + return LoadCached("ArchivoNarrow-Italic.ttf"); + } + else if (subFamily == FontSubFamily.Bold) + { + return LoadCached("ArchivoNarrow-Bold.ttf"); + } + else if(subFamily == FontSubFamily.BoldItalic) + { + return LoadCached("ArchivoNarrow-BoldItalic.ttf"); + } + return LoadCached("ArchivoNarrow-Regular.ttf"); + } + + private static OpenTypeFont LoadCached(string resourceName) + { + lock (_lock) + { + if (_cache.TryGetValue(resourceName, out var font)) + return font; + + var assembly = Assembly.GetExecutingAssembly(); + var fullResourceName = $"EPPlus.Fonts.OpenType.Resources.{resourceName}"; + + using (var stream = assembly.GetManifestResourceStream(fullResourceName)) + { + if (stream == null) + { + throw new InvalidOperationException( + $"Embedded font resource not found: {resourceName}. " + + "This is a bug in EPPlus.Fonts.OpenType - please report it."); + } + + font = OpenTypeFonts.GetFromBytes(bytes: ReadStreamFully(stream)); + _cache[resourceName] = font; + return font; + } + } + } + + /// + /// Reads all bytes from a stream into a byte array. + /// .NET 3.5 compatible (no CopyTo available). + /// + private static byte[] ReadStreamFully(Stream stream) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + // Try to use stream length if available (e.g., MemoryStream, FileStream) + if (stream.CanSeek) + { + long length = stream.Length - stream.Position; + if (length > int.MaxValue) + throw new InvalidOperationException("Stream is too large to read into memory"); + + byte[] buffer = new byte[(int)length]; + int offset = 0; + int remaining = (int)length; + + while (remaining > 0) + { + int read = stream.Read(buffer, offset, remaining); + if (read <= 0) + throw new EndOfStreamException("Stream ended before reading all bytes"); + + offset += read; + remaining -= read; + } + + return buffer; + } + else + { + // Non-seekable stream (rare for embedded resources, but handle it) + // Use MemoryStream to accumulate bytes + using (var ms = new MemoryStream()) + { + byte[] buffer = new byte[8192]; // 8KB buffer + int bytesRead; + + while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) + { + ms.Write(buffer, 0, bytesRead); + } + + return ms.ToArray(); + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/EpplusFontConfiguration.cs b/src/EPPlus.Fonts.OpenType/EpplusFontConfiguration.cs new file mode 100644 index 0000000000..e39aca5b5e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/EpplusFontConfiguration.cs @@ -0,0 +1,168 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/27/2026 EPPlus Software AB Replaces FontResolutionConfig + 05/06/2026 EPPlus Software AB Property-based transactional configuration + 05/20/2026 EPPlus Software AB Added per-script glyph fallback configuration + *************************************************************************************************/ +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.FontResolver +{ + /// + /// Concrete implementation of . + /// Managed exclusively by — not instantiated by user code. + /// Mutations are intended to happen inside an OpenTypeFonts.Configure callback, + /// after which reads the resulting state as a snapshot and + /// rebuilds the resolver. + /// + internal class EpplusFontConfiguration : IEpplusFontConfiguration + { + private readonly List _fontDirectories = new List(); + private readonly Dictionary _fontFallbacks = + new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _scriptFallbacks = + new Dictionary(); + + public EpplusFontConfiguration() + { + SearchSystemDirectories = true; + ApplyDefaultScriptFallbacks(); + } + + /// + public IList FontDirectories + { + get { return _fontDirectories; } + } + + /// + public bool SearchSystemDirectories { get; set; } + + /// + public IFontResolver FontResolver { get; set; } + + /// + public IDictionary FontFallbacks + { + get { return _fontFallbacks; } + } + + /// + public void SetScriptFallback(UnicodeScript script, params string[] fallbackFontNames) + { + if (fallbackFontNames == null) + { + _scriptFallbacks[script] = new string[0]; + return; + } + + // Copy to insulate against caller mutating the array after the call. + var copy = new string[fallbackFontNames.Length]; + Array.Copy(fallbackFontNames, copy, fallbackFontNames.Length); + _scriptFallbacks[script] = copy; + } + + /// + public void Reset() + { + _fontDirectories.Clear(); + SearchSystemDirectories = true; + FontResolver = null; + _fontFallbacks.Clear(); + _scriptFallbacks.Clear(); + ApplyDefaultScriptFallbacks(); + } + + // ----------------------------------------------------------------------------------------- + // Internal API — consumed by DefaultFontResolver and DefaultFontProvider + // in the same assembly. + // ----------------------------------------------------------------------------------------- + + /// + /// Returns the user-configured fallback chain for the given font name, or null if none + /// is configured. Case-insensitive lookup. + /// + internal string[] GetFallbacks(string fontName) + { + string[] result; + return _fontFallbacks.TryGetValue(fontName, out result) ? result : null; + } + + /// + /// Returns the configured fallback chain for the given Unicode script, or null if + /// none is configured. A returned empty array means fallback is explicitly disabled + /// for the script. + /// + internal string[] GetScriptFallback(UnicodeScript script) + { + string[] result; + return _scriptFallbacks.TryGetValue(script, out result) ? result : null; + } + + // ----------------------------------------------------------------------------------------- + // Default per-script chains + // + // These cover the scripts most likely to appear in Office documents. Each chain prefers + // platform-native fonts first (Windows / macOS), then Noto as a Linux / open-source + // fallback. Chains stay within a single language family — falling back from Japanese + // to Chinese, or vice versa, would render incorrect glyph forms for shared CJK + // ideographs. + // + // Emoji and Math are intentionally NOT in this table. They are served by EPPlus's + // bundled Noto Emoji and Noto Math fonts and are routed before per-script lookup. + // ----------------------------------------------------------------------------------------- + + private void ApplyDefaultScriptFallbacks() + { + _scriptFallbacks[UnicodeScript.Han] = new[] + { + "Microsoft YaHei", "SimSun", "Noto Sans CJK SC", "PingFang SC" + }; + + _scriptFallbacks[UnicodeScript.Hiragana] = new[] + { + "Yu Gothic", "MS Gothic", "Meiryo", "Noto Sans CJK JP" + }; + + _scriptFallbacks[UnicodeScript.Katakana] = new[] + { + "Yu Gothic", "MS Gothic", "Meiryo", "Noto Sans CJK JP" + }; + + _scriptFallbacks[UnicodeScript.Hangul] = new[] + { + "Malgun Gothic", "Gulim", "Noto Sans CJK KR" + }; + + _scriptFallbacks[UnicodeScript.Arabic] = new[] + { + "Segoe UI", "Tahoma", "Arial", "Noto Sans Arabic" + }; + + _scriptFallbacks[UnicodeScript.Hebrew] = new[] + { + "Segoe UI", "Tahoma", "Arial", "Noto Sans Hebrew" + }; + + _scriptFallbacks[UnicodeScript.Thai] = new[] + { + "Tahoma", "Leelawadee UI", "Noto Sans Thai" + }; + + _scriptFallbacks[UnicodeScript.Devanagari] = new[] + { + "Mangal", "Nirmala UI", "Noto Sans Devanagari" + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontCache/CachedOpenTypeFont.cs b/src/EPPlus.Fonts.OpenType/FontCache/CachedOpenTypeFont.cs new file mode 100644 index 0000000000..61cdae5573 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontCache/CachedOpenTypeFont.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.FontCache +{ + internal class CachedOpenTypeFont + { + public OpenTypeFont Font { get; set; } + + public bool IsLoaded { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontCache/OpenTypeFontCache.cs b/src/EPPlus.Fonts.OpenType/FontCache/OpenTypeFontCache.cs new file mode 100644 index 0000000000..c24af917c8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontCache/OpenTypeFontCache.cs @@ -0,0 +1,137 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/26/2026 EPPlus Software AB Added overloads accepting prebuilt cache keys + 05/13/2026 EPPlus Software AB Converted to instance class owned by OpenTypeFontEngine + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace EPPlus.Fonts.OpenType.FontCache +{ + /// + /// Cache of parsed OpenTypeFont instances keyed by a per-engine cache key. + /// One instance per OpenTypeFontEngine — two engines never share parsed fonts because + /// their resolver configurations may produce different fonts for the same name. + /// All operations are thread-safe within a single instance. + /// + internal class OpenTypeFontCache + { + private readonly Dictionary _cache = + new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly object _syncRoot = new object(); + + internal void Clear() + { + lock (_syncRoot) + { + _cache.Clear(); + } + } + + /// + /// Checks if a font is present in the cache (loaded or loading). + /// + public bool Contains(string cacheKey) + { + lock (_syncRoot) + { + return _cache.ContainsKey(cacheKey); + } + } + + /// + /// Creates a placeholder entry to indicate that font loading has begun. + /// This prevents multiple threads from starting to load the same font. + /// + public void BeginCache(string cacheKey) + { + lock (_syncRoot) + { + if (!_cache.ContainsKey(cacheKey)) + { + _cache[cacheKey] = new CachedOpenTypeFont() + { + IsLoaded = false, + Font = null + }; + } + } + } + + /// + /// Adds or updates a fully loaded font using a prebuilt cache key. + /// Signals all waiting threads that the font is now available. + /// + public void AddToCache(OpenTypeFont font, string cacheKey) + { + lock (_syncRoot) + { + if (_cache.ContainsKey(cacheKey)) + { + _cache[cacheKey].Font = font; + _cache[cacheKey].IsLoaded = true; + } + else + { + _cache[cacheKey] = new CachedOpenTypeFont + { + Font = font, + IsLoaded = true + }; + } + + // Signal all waiting threads that the font is loaded + Monitor.PulseAll(_syncRoot); + } + } + + /// + /// Retrieves a font from cache using a prebuilt cache key. + /// Waits if the font is currently being loaded by another thread. + /// Returns null if font is not in cache or if timeout occurs while waiting. + /// + public CachedOpenTypeFont GetFromCache(string cacheKey) + { + lock (_syncRoot) + { + if (_cache.TryGetValue(cacheKey, out var cached)) + { + // If already loaded, return immediately + if (cached.IsLoaded && cached.Font != null) + return cached; + + // Wait for another thread to finish loading + var timeout = TimeSpan.FromSeconds(2); + var start = DateTime.UtcNow; + + while ((DateTime.UtcNow - start) < timeout) + { + // CRITICAL: Retrieve from dictionary again after Wait()! + // The 'cached' reference may be stale after another thread updates the cache + if (_cache.TryGetValue(cacheKey, out cached) && cached.IsLoaded && cached.Font != null) + return cached; + + Monitor.Wait(_syncRoot, TimeSpan.FromMilliseconds(50)); + } + + // One final check after timeout + if (_cache.TryGetValue(cacheKey, out cached) && cached.IsLoaded && cached.Font != null) + return cached; + + return null; + } + return null; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontLocalization/LanguageMapping.cs b/src/EPPlus.Fonts.OpenType/FontLocalization/LanguageMapping.cs new file mode 100644 index 0000000000..393fb49f39 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontLocalization/LanguageMapping.cs @@ -0,0 +1,36 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.FontLocalization +{ + public class LanguageMapping + { + public int code { get; set; } + + public Languages Language { get; set; } + + internal static LanguageMapping Create(int code, Languages language) + { + return new LanguageMapping + { + code = code, + Language = language + }; + } + + public override string ToString() + { + return Language.ToString(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontLocalization/Languages.cs b/src/EPPlus.Fonts.OpenType/FontLocalization/Languages.cs new file mode 100644 index 0000000000..e89fc60000 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontLocalization/Languages.cs @@ -0,0 +1,184 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.FontLocalization +{ + public enum Languages + { + Afrikaans, + Albanian, + Alsatian, + Amharic, + Arabic, + Armenian, + Assamese, + Aymara, + Azeri_Cyrillic, + Azeri_Arabic, + Azeri_Latin, + Bashkir, + Basque, + Belarusian, + Bengali, + Bosnian_Cyrillic, + Bosnian_Latin, + Breton, + Bulgarian, + Burmese, + Byelorussian, + Catalan, + Chinese, + Chinese_Traditional, + Chinese_Simplified, + Corsican, + Croatian, + Croatian_Latin, + Czech, + Danish, + Dari, + Divehi, + Dutch, + Dzongkha, + English, + Estonian, + Faroese, + Farsi, + Filipino, + Finnish, + Flemish, + French, + Frisian, + Galician, + Galla, + Georgian, + German, + Greek, + Greek_Polytonic, + Greenlandic, + Gujarati, + Gurani, + Hausa_Latin, + Hebrew, + Hindi, + Hungarian, + Icelandic, + Igbo, + Indonesian, + Inuktitut, + Inuktitut_Latin, + Irish, + isiXhosa, + isiZulu, + Italian, + Japanese, + Javanese_Roman, + Kannada, + Kashmiri, + Kazakh, + Khmer, + Kiche, + Kinyarwanda, + Kirghiz, + Kiswahili, + Konkani, + Korean, + Kurdish, + Kyrgyz, + Lao, + Latin, + Latvian, + Lithuanian, + LowerSorbian, + Luxembourgish, + Macedonian, + Malay, + Malay_Roman, + Malay_Arabic, + Malayalam, + Maltese, + Maori, + Mapudungun, + Marathi, + Mohawk, + Moldavian, + Mongolian_Cyrillic, + Mongolian_Traditional, + Nepali, + Norwegian, + Norwegian_Bokmal, + Norwegian_Nynorsk, + Occitan, + Odia_formerlyOriya, + Oriya, + Pashto, + Polish, + Portuguese, + Punjabi, + Quechua, + Romanian, + Romansh, + Rundi, + Russian, + Sami, + Sami_Inari, + Sami_Lule, + Sami_Northern, + Sami_Skolt, + Sami_Southern, + Sanskrit, + Serbian, + Serbian_Cyrillic, + Serbian_Latin, + Sesotho_saLeboa, + Setswana, + Sindhi, + Sinhala, + Sinhalese, + Slovak, + Slovenian, + Somali, + Spanish_ModernSort, + Spanish_TraditionalSort, + Spanish, + Sundanese_Roman, + Swahili, + Swedish, + Syriac, + Tagalog, + Tajiki, + Tajik_Cyrillic, + Tamazight_Latin, + Tamil, + Tatar, + Telugu, + Thai, + Tibetan, + Tigrinya, + Tongan, + Turkish, + Turkmen, + Uighur, + Ukrainian, + UpperSorbian, + Urdu, + Uzbek, + Uzbek_Cyrillic, + Uzbek_Latin, + Vietnamese, + Welsh, + Wolof, + Yakut, + Yi, + Yiddish, + Yoruba + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontLocalization/MacintoshLanguageMappings.cs b/src/EPPlus.Fonts.OpenType/FontLocalization/MacintoshLanguageMappings.cs new file mode 100644 index 0000000000..1f9525c69b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontLocalization/MacintoshLanguageMappings.cs @@ -0,0 +1,170 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/27/2026 EPPlus Software AB Thread-safe initialization + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.FontLocalization +{ + internal static class MacintoshLanguageMappings + { + private static readonly object _syncRoot = new object(); + private static volatile bool _initialized = false; + private static readonly Dictionary _mappings = new Dictionary(); + + private static void AddMapping(int hexNumber, Languages language) + { + // Called only within lock, no additional lock needed + var mapping = LanguageMapping.Create(hexNumber, language); + _mappings.Add(mapping.code, mapping); + } + + private static void CreateMappings() + { + AddMapping(0, Languages.English); + AddMapping(1, Languages.French); + AddMapping(2, Languages.German); + AddMapping(3, Languages.Italian); + AddMapping(4, Languages.Dutch); + AddMapping(5, Languages.Swedish); + AddMapping(6, Languages.Spanish); + AddMapping(7, Languages.Danish); + AddMapping(8, Languages.Portuguese); + AddMapping(9, Languages.Norwegian); + AddMapping(10, Languages.Hebrew); + AddMapping(11, Languages.Japanese); + AddMapping(12, Languages.Arabic); + AddMapping(13, Languages.Finnish); + AddMapping(14, Languages.Greek); + AddMapping(15, Languages.Icelandic); + AddMapping(16, Languages.Maltese); + AddMapping(17, Languages.Turkish); + AddMapping(18, Languages.Croatian); + AddMapping(19, Languages.Chinese_Traditional); + AddMapping(20, Languages.Urdu); + AddMapping(21, Languages.Hindi); + AddMapping(22, Languages.Thai); + AddMapping(23, Languages.Korean); + AddMapping(24, Languages.Lithuanian); + AddMapping(25, Languages.Polish); + AddMapping(26, Languages.Hungarian); + AddMapping(27, Languages.Estonian); + AddMapping(28, Languages.Latvian); + AddMapping(29, Languages.Sami); + AddMapping(30, Languages.Faroese); + AddMapping(31, Languages.Farsi); + AddMapping(32, Languages.Russian); + AddMapping(33, Languages.Chinese_Simplified); + AddMapping(34, Languages.Flemish); + AddMapping(35, Languages.Irish); + AddMapping(36, Languages.Albanian); + AddMapping(37, Languages.Romanian); + AddMapping(38, Languages.Czech); + AddMapping(39, Languages.Slovak); + AddMapping(40, Languages.Slovenian); + AddMapping(41, Languages.Yiddish); + AddMapping(42, Languages.Serbian); + AddMapping(43, Languages.Macedonian); + AddMapping(44, Languages.Bulgarian); + AddMapping(45, Languages.Ukrainian); + AddMapping(46, Languages.Byelorussian); + AddMapping(47, Languages.Uzbek); + AddMapping(48, Languages.Kazakh); + AddMapping(49, Languages.Azeri_Cyrillic); + AddMapping(50, Languages.Azeri_Arabic); + AddMapping(51, Languages.Armenian); + AddMapping(52, Languages.Georgian); + AddMapping(53, Languages.Moldavian); + AddMapping(54, Languages.Kirghiz); + AddMapping(55, Languages.Tajiki); + AddMapping(56, Languages.Turkmen); + AddMapping(57, Languages.Mongolian_Traditional); + AddMapping(58, Languages.Mongolian_Cyrillic); + AddMapping(59, Languages.Pashto); + AddMapping(60, Languages.Kurdish); + AddMapping(61, Languages.Kashmiri); + AddMapping(62, Languages.Sindhi); + AddMapping(63, Languages.Tibetan); + AddMapping(64, Languages.Nepali); + AddMapping(65, Languages.Sanskrit); + AddMapping(66, Languages.Marathi); + AddMapping(67, Languages.Bengali); + AddMapping(68, Languages.Assamese); + AddMapping(69, Languages.Gujarati); + AddMapping(70, Languages.Punjabi); + AddMapping(71, Languages.Oriya); + AddMapping(72, Languages.Malayalam); + AddMapping(73, Languages.Kannada); + AddMapping(74, Languages.Tamil); + AddMapping(75, Languages.Telugu); + AddMapping(76, Languages.Sinhalese); + AddMapping(77, Languages.Burmese); + AddMapping(78, Languages.Khmer); + AddMapping(79, Languages.Lao); + AddMapping(80, Languages.Vietnamese); + AddMapping(81, Languages.Indonesian); + AddMapping(82, Languages.Tagalog); + AddMapping(83, Languages.Malay_Roman); + AddMapping(84, Languages.Malay_Arabic); + AddMapping(85, Languages.Amharic); + AddMapping(86, Languages.Tigrinya); + AddMapping(87, Languages.Galla); + AddMapping(88, Languages.Somali); + AddMapping(89, Languages.Swahili); + AddMapping(90, Languages.Kinyarwanda); + AddMapping(91, Languages.Rundi); + AddMapping(128, Languages.Welsh); + AddMapping(129, Languages.Basque); + AddMapping(130, Languages.Catalan); + AddMapping(131, Languages.Latin); + AddMapping(132, Languages.Quechua); + AddMapping(133, Languages.Gurani); + AddMapping(134, Languages.Aymara); + AddMapping(135, Languages.Tatar); + AddMapping(136, Languages.Uighur); + AddMapping(137, Languages.Dzongkha); + AddMapping(138, Languages.Javanese_Roman); + AddMapping(139, Languages.Sundanese_Roman); + AddMapping(140, Languages.Galician); + AddMapping(141, Languages.Afrikaans); + AddMapping(142, Languages.Breton); + AddMapping(143, Languages.Inuktitut); + AddMapping(144, Languages.Galician); + AddMapping(145, Languages.Galician); + AddMapping(146, Languages.Irish); + AddMapping(147, Languages.Tongan); + AddMapping(148, Languages.Greek_Polytonic); + AddMapping(149, Languages.Greenlandic); + AddMapping(150, Languages.Azeri_Latin); + } + + public static IDictionary Mappings + { + get + { + // Double-checked locking pattern, compatible with .NET 3.5+ + if (!_initialized) + { + lock (_syncRoot) + { + if (!_initialized) + { + CreateMappings(); + _initialized = true; + } + } + } + return _mappings; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontLocalization/WindowsLanguageMappings.cs b/src/EPPlus.Fonts.OpenType/FontLocalization/WindowsLanguageMappings.cs new file mode 100644 index 0000000000..7c98224f3e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontLocalization/WindowsLanguageMappings.cs @@ -0,0 +1,279 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/27/2026 EPPlus Software AB Thread-safe initialization + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.FontLocalization +{ + internal static class WindowsLanguageMappings + { + private static readonly object _syncRoot = new object(); + private static volatile bool _initialized = false; + private static readonly Dictionary _mappings = new Dictionary(); + + private static void AddMappping(int hexNumber, Languages language) + { + // Called only within lock during initialization, no additional lock needed + if (_mappings.ContainsKey(hexNumber)) return; + + var mapping = LanguageMapping.Create(hexNumber, language); + _mappings.Add(mapping.code, mapping); + } + + private static void CreateMappings() + { + AddMappping(0x0436, Languages.Afrikaans); + AddMappping(0x041C, Languages.Albanian); + AddMappping(0x0484, Languages.Alsatian); + AddMappping(0x045E, Languages.Amharic); + + AddMappping(0x1401, Languages.Arabic); + AddMappping(0x3C01, Languages.Arabic); + AddMappping(0x0C01, Languages.Arabic); + AddMappping(0x0801, Languages.Arabic); + AddMappping(0x2C01, Languages.Arabic); + AddMappping(0x3401, Languages.Arabic); + AddMappping(0x3001, Languages.Arabic); + AddMappping(0x1001, Languages.Arabic); + AddMappping(0x1801, Languages.Arabic); + AddMappping(0x2001, Languages.Arabic); + AddMappping(0x4001, Languages.Arabic); + AddMappping(0x2801, Languages.Arabic); + AddMappping(0x1C01, Languages.Arabic); + AddMappping(0x3801, Languages.Arabic); + AddMappping(0x2401, Languages.Arabic); + AddMappping(0x0401, Languages.Arabic); + AddMappping(0x2801, Languages.Arabic); + AddMappping(0x1401, Languages.Arabic); + AddMappping(0x0429, Languages.Dari); + AddMappping(0x042B, Languages.Armenian); + AddMappping(0x044D, Languages.Assamese); + AddMappping(0x082C, Languages.Azeri_Cyrillic); + AddMappping(0x042C, Languages.Azeri_Latin); + AddMappping(0x046D, Languages.Bashkir); + AddMappping(0x042D, Languages.Basque); + AddMappping(0x0423, Languages.Belarusian); + AddMappping(0x0845, Languages.Bengali); + AddMappping(0x0445, Languages.Bengali); + AddMappping(0x201A, Languages.Bosnian_Cyrillic); + AddMappping(0x141A, Languages.Bosnian_Latin); + AddMappping(0x047E, Languages.Breton); + AddMappping(0x0402, Languages.Bulgarian); + AddMappping(0x0403, Languages.Catalan); + AddMappping(0x0C04, Languages.Chinese_Traditional); + AddMappping(0x1404, Languages.Chinese_Traditional); + AddMappping(0x0804, Languages.Chinese_Simplified); + AddMappping(0x1004, Languages.Chinese_Simplified); + AddMappping(0x0404, Languages.Chinese_Traditional); + AddMappping(0x0483, Languages.Corsican); + AddMappping(0x041A, Languages.Croatian); + AddMappping(0x101A, Languages.Croatian_Latin); + AddMappping(0x0405, Languages.Czech); + AddMappping(0x0406, Languages.Danish); + AddMappping(0x048C, Languages.Dari); + AddMappping(0x0465, Languages.Divehi); + AddMappping(0x0413, Languages.Dutch); + AddMappping(0x0813, Languages.Dutch); + + AddMappping(0x0C09, Languages.English); + AddMappping(0x2809, Languages.English); + AddMappping(0x1009, Languages.English); + AddMappping(0x2409, Languages.English); + AddMappping(0x4009, Languages.English); + AddMappping(0x1809, Languages.English); + AddMappping(0x2009, Languages.English); + AddMappping(0x4409, Languages.English); + AddMappping(0x1409, Languages.English); + AddMappping(0x3409, Languages.English); + AddMappping(0x4809, Languages.English); + AddMappping(0x1C09, Languages.English); + AddMappping(0x2C09, Languages.English); + AddMappping(0x0809, Languages.English); + AddMappping(0x0409, Languages.English); + AddMappping(0x3009, Languages.English); + + AddMappping(0x0425, Languages.Estonian); + AddMappping(0x0438, Languages.Faroese); + AddMappping(0x0464, Languages.Filipino); + AddMappping(0x040B, Languages.Finnish); + AddMappping(0x080C, Languages.French); + AddMappping(0x0C0C, Languages.French); + AddMappping(0x040C, Languages.French); + AddMappping(0x140C, Languages.French); + AddMappping(0x180C, Languages.French); + AddMappping(0x100C, Languages.French); + AddMappping(0x0462, Languages.Frisian); + + AddMappping(0x0456, Languages.Galician); + AddMappping(0x0437, Languages.Georgian); + AddMappping(0x0C07, Languages.German); + AddMappping(0x0407, Languages.German); + AddMappping(0x1407, Languages.German); + AddMappping(0x1007, Languages.German); + AddMappping(0x0807, Languages.German); + AddMappping(0x0408, Languages.Greek); + AddMappping(0x046F, Languages.Greenlandic); + AddMappping(0x0447, Languages.Gujarati); + + AddMappping(0x0468, Languages.Hausa_Latin); + AddMappping(0x040D, Languages.Hebrew); + AddMappping(0x0439, Languages.Hindi); + AddMappping(0x040E, Languages.Hungarian); + AddMappping(0x040F, Languages.Icelandic); + AddMappping(0x0470, Languages.Igbo); + AddMappping(0x0421, Languages.Indonesian); + AddMappping(0x045D, Languages.Inuktitut); + AddMappping(0x085D, Languages.Inuktitut_Latin); + AddMappping(0x083C, Languages.Irish); + AddMappping(0x0434, Languages.isiXhosa); + AddMappping(0x0435, Languages.isiZulu); + + AddMappping(0x0410, Languages.Italian); + AddMappping(0x0810, Languages.Italian); + AddMappping(0x0411, Languages.Japanese); + AddMappping(0x044B, Languages.Kannada); + AddMappping(0x043F, Languages.Kazakh); + AddMappping(0x0453, Languages.Khmer); + AddMappping(0x0486, Languages.Kiche); + AddMappping(0x0487, Languages.Kinyarwanda); + AddMappping(0x0441, Languages.Kiswahili); + AddMappping(0x0457, Languages.Konkani); + + AddMappping(0x0412, Languages.Korean); + AddMappping(0x0440, Languages.Kyrgyz); + AddMappping(0x0454, Languages.Lao); + AddMappping(0x0426, Languages.Latvian); + AddMappping(0x0427, Languages.Lithuanian); + AddMappping(0x082E, Languages.LowerSorbian); + AddMappping(0x046E, Languages.Luxembourgish); + AddMappping(0x042F, Languages.Macedonian); + AddMappping(0x083E, Languages.Malay); + AddMappping(0x043E, Languages.Malay); + + AddMappping(0x044C, Languages.Malayalam); + AddMappping(0x043A, Languages.Maltese); + AddMappping(0x0481, Languages.Maori); + AddMappping(0x047A, Languages.Mapudungun); + AddMappping(0x044E, Languages.Marathi); + AddMappping(0x047C, Languages.Mohawk); + AddMappping(0x0450, Languages.Mongolian_Cyrillic); + AddMappping(0x0850, Languages.Mongolian_Traditional); + AddMappping(0x0461, Languages.Nepali); + + AddMappping(0x0414, Languages.Norwegian_Bokmal); + AddMappping(0x0814, Languages.Norwegian_Nynorsk); + AddMappping(0x0482, Languages.Occitan); + AddMappping(0x0448, Languages.Odia_formerlyOriya); + AddMappping(0x0463, Languages.Pashto); + AddMappping(0x0415, Languages.Polish); + AddMappping(0x0416, Languages.Portuguese); + AddMappping(0x0816, Languages.Portuguese); + + AddMappping(0x0446, Languages.Punjabi); + AddMappping(0x046B, Languages.Quechua); + AddMappping(0x086B, Languages.Quechua); + AddMappping(0x0C6B, Languages.Quechua); + AddMappping(0x0418, Languages.Romanian); + AddMappping(0x0417, Languages.Romansh); + AddMappping(0x0419, Languages.Russian); + AddMappping(0x243B, Languages.Sami_Inari); + AddMappping(0x103B, Languages.Sami_Lule); + AddMappping(0x143B, Languages.Sami_Lule); + + AddMappping(0x0C3B, Languages.Sami_Northern); + AddMappping(0x043B, Languages.Sami_Northern); + AddMappping(0x083B, Languages.Sami_Northern); + AddMappping(0x203B, Languages.Sami_Skolt); + AddMappping(0x183B, Languages.Sami_Southern); + AddMappping(0x1C3B, Languages.Sami_Southern); + AddMappping(0x044F, Languages.Sanskrit); + AddMappping(0x1C1A, Languages.Serbian_Cyrillic); + AddMappping(0x0C1A, Languages.Serbian_Cyrillic); + AddMappping(0x181A, Languages.Serbian_Latin); + AddMappping(0x081A, Languages.Serbian_Latin); + + AddMappping(0x046C, Languages.Sesotho_saLeboa); + AddMappping(0x0432, Languages.Setswana); + AddMappping(0x045B, Languages.Sinhala); + AddMappping(0x041B, Languages.Slovak); + AddMappping(0x0424, Languages.Slovenian); + AddMappping(0x2C0A, Languages.Spanish); + AddMappping(0x400A, Languages.Spanish); + AddMappping(0x340A, Languages.Spanish); + AddMappping(0x240A, Languages.Spanish); + AddMappping(0x140A, Languages.Spanish); + AddMappping(0x1C0A, Languages.Spanish); + AddMappping(0x300A, Languages.Spanish); + AddMappping(0x440A, Languages.Spanish); + AddMappping(0x100A, Languages.Spanish); + AddMappping(0x480A, Languages.Spanish); + AddMappping(0x080A, Languages.Spanish); + AddMappping(0x4C0A, Languages.Spanish); + AddMappping(0x180A, Languages.Spanish); + AddMappping(0x3C0A, Languages.Spanish); + AddMappping(0x280A, Languages.Spanish); + AddMappping(0x500A, Languages.Spanish); + AddMappping(0x0C0A, Languages.Spanish_ModernSort); + AddMappping(0x040A, Languages.Spanish_TraditionalSort); + AddMappping(0x540A, Languages.Spanish); + AddMappping(0x380A, Languages.Spanish); + AddMappping(0x200A, Languages.Spanish); + + AddMappping(0x081D, Languages.Swedish); + AddMappping(0x041D, Languages.Swedish); + AddMappping(0x045A, Languages.Syriac); + AddMappping(0x0428, Languages.Tajik_Cyrillic); + AddMappping(0x085F, Languages.Tamazight_Latin); + AddMappping(0x0449, Languages.Tamil); + AddMappping(0x0444, Languages.Tatar); + AddMappping(0x044A, Languages.Telugu); + AddMappping(0x041E, Languages.Thai); + AddMappping(0x0451, Languages.Tibetan); + AddMappping(0x041F, Languages.Turkish); + AddMappping(0x0442, Languages.Turkmen); + AddMappping(0x0480, Languages.Uighur); + AddMappping(0x0422, Languages.Ukrainian); + + AddMappping(0x042E, Languages.UpperSorbian); + AddMappping(0x0420, Languages.Urdu); + AddMappping(0x0843, Languages.Uzbek_Cyrillic); + AddMappping(0x0443, Languages.Uzbek_Latin); + AddMappping(0x042A, Languages.Vietnamese); + AddMappping(0x0452, Languages.Welsh); + AddMappping(0x0488, Languages.Wolof); + AddMappping(0x0485, Languages.Yakut); + AddMappping(0x0478, Languages.Yi); + AddMappping(0x046A, Languages.Yoruba); + } + + public static IDictionary Mappings + { + get + { + // Double-checked locking pattern, compatible with .NET 3.5+ + if (!_initialized) + { + lock (_syncRoot) + { + if (!_initialized) + { + CreateMappings(); + _initialized = true; + } + } + } + return _mappings; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontResolver/BuiltinFontFallbackChains.Generated.cs b/src/EPPlus.Fonts.OpenType/FontResolver/BuiltinFontFallbackChains.Generated.cs new file mode 100644 index 0000000000..14a089f712 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontResolver/BuiltinFontFallbackChains.Generated.cs @@ -0,0 +1,106 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + *************************************************************************************************/ +// +// This file was generated by EPPlus.Tools.Fonts. Do not edit by hand. +// Generated on 2026-05-19 11:22:31Z +// Entries: 56 +// + +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.FontResolver +{ + /// + /// Built-in font fallback chains. Each entry maps a font family name to an ordered list + /// of fallback names. Used by DefaultFontResolver when an exact match cannot be found + /// and the user has not configured a custom fallback for the requested font. + /// + internal static class BuiltinFontFallbackChains + { + private static readonly Dictionary _chains = BuildChains(); + + /// + /// Returns the ordered fallback chain for the given font name, or null if no chain is defined. + /// Lookup is case-insensitive. + /// + internal static string[] GetFallbacks(string fontName) + { + if (string.IsNullOrEmpty(fontName)) + return null; + + string[] result; + return _chains.TryGetValue(fontName, out result) ? result : null; + } + + private static Dictionary BuildChains() + { + var d = new Dictionary(StringComparer.OrdinalIgnoreCase); + + d[@"Aptos"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Aptos Display"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Aptos Light"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial" }; + d[@"Aptos Mono"] = new string[] { @"Cascadia Mono", @"Cascadia Code", @"Consolas", @"Liberation Mono", @"Courier New" }; + d[@"Aptos Narrow"] = new string[] { @"Liberation Sans Narrow", @"Arial Narrow", @"Carlito", @"Liberation Sans", @"Arial" }; + d[@"Aptos SemiBold"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial" }; + d[@"Arabic Transparent"] = new string[] { @"Arial" }; + d[@"Arabic Transparent Bold"] = new string[] { @"Arial Bold" }; + d[@"Arial"] = new string[] { @"Liberation Sans", @"Helvetica" }; + d[@"Arial Black"] = new string[] { @"Liberation Sans", @"Arial" }; + d[@"Arial Narrow"] = new string[] { @"Liberation Sans Narrow", @"Liberation Sans" }; + d[@"Book Antiqua"] = new string[] { @"Palatino Linotype", @"Palatino", @"Liberation Serif", @"Times New Roman" }; + d[@"Bookman Old Style"] = new string[] { @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Caladea"] = new string[] { @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Calibri"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Calibri Light"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Cambria"] = new string[] { @"Caladea", @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Cambria Math"] = new string[] { @"Latin Modern Math", @"STIX Two Math", @"Caladea", @"Liberation Serif" }; + d[@"Candara"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial" }; + d[@"Carlito"] = new string[] { @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Cascadia Code"] = new string[] { @"Cascadia Mono", @"Consolas", @"Liberation Mono", @"Courier New" }; + d[@"Cascadia Mono"] = new string[] { @"Cascadia Code", @"Consolas", @"Liberation Mono", @"Courier New" }; + d[@"Century Gothic"] = new string[] { @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Century Schoolbook"] = new string[] { @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Comic Sans MS"] = new string[] { @"Liberation Sans", @"Arial" }; + d[@"Consolas"] = new string[] { @"Cascadia Mono", @"Cascadia Code", @"Liberation Mono", @"Courier New" }; + d[@"Constantia"] = new string[] { @"Caladea", @"Liberation Serif", @"Georgia", @"Times New Roman" }; + d[@"Corbel"] = new string[] { @"Carlito", @"Liberation Sans", @"Arial" }; + d[@"Courier"] = new string[] { @"Courier New", @"Liberation Mono" }; + d[@"Courier New"] = new string[] { @"Liberation Mono", @"Courier" }; + d[@"DejaVu Sans"] = new string[] { @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"DejaVu Sans Condensed"] = new string[] { @"DejaVu Sans", @"Liberation Sans", @"Arial" }; + d[@"DejaVu Sans Mono"] = new string[] { @"Liberation Mono", @"Courier New", @"Courier" }; + d[@"Garamond"] = new string[] { @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Georgia"] = new string[] { @"Liberation Serif", @"Times New Roman", @"Times" }; + d[@"Helvetica"] = new string[] { @"Arial", @"Liberation Sans" }; + d[@"Helvetica Neue"] = new string[] { @"Helvetica", @"Arial", @"Liberation Sans" }; + d[@"Impact"] = new string[] { @"Liberation Sans Narrow", @"Arial Narrow", @"Arial Black", @"Arial" }; + d[@"Liberation Mono"] = new string[] { @"Courier New", @"Courier" }; + d[@"Liberation Sans"] = new string[] { @"Arial", @"Helvetica" }; + d[@"Liberation Sans Narrow"] = new string[] { @"Arial Narrow", @"Liberation Sans", @"Arial" }; + d[@"Liberation Serif"] = new string[] { @"Times New Roman", @"Times" }; + d[@"Lucida Console"] = new string[] { @"DejaVu Sans Mono", @"Liberation Mono", @"Consolas", @"Courier New" }; + d[@"Lucida Sans Unicode"] = new string[] { @"DejaVu Sans", @"Liberation Sans", @"Arial" }; + d[@"MS Sans Serif"] = new string[] { @"Arial", @"Liberation Sans", @"Helvetica" }; + d[@"MS Serif"] = new string[] { @"Times New Roman", @"Liberation Serif", @"Times" }; + d[@"Palatino"] = new string[] { @"Palatino Linotype", @"Book Antiqua", @"Liberation Serif", @"Times New Roman" }; + d[@"Palatino Linotype"] = new string[] { @"Palatino", @"Book Antiqua", @"Liberation Serif", @"Times New Roman" }; + d[@"Segoe Print"] = new string[] { @"Comic Sans MS", @"Liberation Sans", @"Arial" }; + d[@"Segoe Script"] = new string[] { @"Comic Sans MS", @"Liberation Sans", @"Arial" }; + d[@"Segoe UI"] = new string[] { @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Tahoma"] = new string[] { @"DejaVu Sans Condensed", @"DejaVu Sans", @"Liberation Sans", @"Arial" }; + d[@"Times"] = new string[] { @"Times New Roman", @"Liberation Serif" }; + d[@"Times New Roman"] = new string[] { @"Liberation Serif", @"Times" }; + d[@"Trebuchet MS"] = new string[] { @"Liberation Sans", @"Arial", @"Helvetica" }; + d[@"Verdana"] = new string[] { @"DejaVu Sans", @"Liberation Sans", @"Arial" }; + + return d; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontLocations.cs b/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontLocations.cs new file mode 100644 index 0000000000..6367448814 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontLocations.cs @@ -0,0 +1,83 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils.Platform; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.FontResolver +{ + internal static class DefaultFontLocations + { + private static string GetWindowsFolder() + { + var winfolder = @"c:\Windows"; +#if !NET35 + var wf = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + if (!string.IsNullOrEmpty(wf) && Directory.Exists(wf)) return wf; +#endif + var ewf = Environment.GetEnvironmentVariable("WINDIR"); + if (!string.IsNullOrEmpty(ewf) && Directory.Exists(ewf)) + { + winfolder = ewf; + } + return winfolder; + } + + internal static readonly List winFontLocations = new List() + { + Path.Combine(GetWindowsFolder(), "Fonts"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\Windows\\Fonts"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Microsoft\\Windows\\Fonts"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\FontCache"), + }; + + internal static readonly List linFontLocations = new List() + { + "/usr/share/fonts", + "/usr/local/share/fonts", + "/usr/share/X11/fonts", + Path.Combine(Environment.GetEnvironmentVariable("HOME") ?? "~", ".fonts"), + Path.Combine(Path.Combine(Path.Combine(Environment.GetEnvironmentVariable("HOME") ?? "~", ".local"), "share"), "fonts"), + }; + + internal static readonly List macFontLocations = new List() + { + "/System/Library/Fonts", + "/Library/Fonts", + "/Network/Library/Fonts", + Path.Combine(Path.Combine(Environment.GetEnvironmentVariable("HOME") ?? "~", "Library"), "Fonts"), + }; + + internal static List GetLocationsCollection(IEnumerable fontDirectories, bool searchSystemDirectories = true) + { + var fontLocations = new List(); + fontLocations.AddRange(fontDirectories ?? Enumerable.Empty()); + + if (searchSystemDirectories) + { + var platform = PlatformUtils.GetPlatform(); + if (platform == PlatformUtils.OperatingSystem.Windows) + fontLocations.AddRange(winFontLocations); + else if (platform == PlatformUtils.OperatingSystem.Mac) + fontLocations.AddRange(macFontLocations); + else + fontLocations.AddRange(linFontLocations); + } + + return fontLocations; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontResolver.cs b/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontResolver.cs new file mode 100644 index 0000000000..813b8bacad --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontResolver/DefaultFontResolver.cs @@ -0,0 +1,146 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/26/2026 EPPlus Software AB Removed caching (moved to OpenTypeFonts) + 02/27/2026 EPPlus Software AB Replaced FontResolutionConfig with EpplusFontConfiguration, added Archivo Narrow fallback + 03/02/2026 EPPlus Software AB TTC support: extract individual font from collection + 05/06/2026 EPPlus Software AB Built-in fallback chains for common Office fonts + 05/06/2026 EPPlus Software AB Extracted IFontScanner and IFontFileReader for testability + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.FontResolver +{ + /// + /// Default IFontResolver implementation that resolves fonts from the file system. + /// Searches additional font directories and optionally system font directories. + /// Supports fallback font chains via EpplusFontConfiguration as well as a built-in + /// metric-aware fallback chain for common Office and system fonts. + /// TTC (TrueType Collection) files are handled transparently by the IFontFileReader. + /// + internal class DefaultFontResolver : IFontResolver, IFontAvailabilityProvider + { + private readonly IEnumerable _fontDirectories; + private readonly bool _searchSystemDirectories; + private readonly EpplusFontConfiguration _config; + private readonly IFontScanner _scanner; + private readonly IFontFileReader _fileReader; + + public DefaultFontResolver( + IEnumerable fontDirectories = null, + bool searchSystemDirectories = true, + EpplusFontConfiguration config = null, + IFontScanner scanner = null, + IFontFileReader fileReader = null) + { + _fontDirectories = fontDirectories ?? Enumerable.Empty(); + _searchSystemDirectories = searchSystemDirectories; + _config = config; + _scanner = scanner ?? new DefaultFontScanner(); + _fileReader = fileReader ?? new DefaultFontFileReader(); + } + + public FontAvailability GetFontAvailability(string fontName, FontSubFamily subFamily) + { + if (string.IsNullOrEmpty(fontName)) + return FontAvailability.NotFound; + + // special case for Archivo Narrow which is distributed as last-resort-font with EPPlus + if (string.Equals("archivo narrow", fontName, StringComparison.OrdinalIgnoreCase)) + { + return FontAvailability.Exact; + } + + var face = _scanner.FindBestMatch( + _fontDirectories, + fontName, + subFamily, + _searchSystemDirectories); + + if (face == null) + return FontAvailability.NotFound; + + // FindBestMatch may return a non-matching face when no real match exists. + // Verify the returned face actually belongs to the requested family. + if (!string.Equals(face.FamilyName, fontName, StringComparison.OrdinalIgnoreCase)) + return FontAvailability.NotFound; + + return face.IsExactMatch + ? FontAvailability.Exact + : FontAvailability.FamilyOnly; + } + + public byte[] ResolveFont(string fontName, FontSubFamily subFamily) + { + // 1. special case for Archivo Narrow which is distributed as last-resort-font with EPPlus + if (string.Equals("archivo narrow", fontName, StringComparison.OrdinalIgnoreCase)) + { + return EmbeddedFonts.LoadArchivoNarrow(subFamily).RawData; + } + + // 2. Try exact match first + var face = _scanner.FindBestMatch( + _fontDirectories, fontName, subFamily, _searchSystemDirectories); + + if (face != null && face.IsExactMatch) + return _fileReader.ReadFontBytes(face); + + // 3. No exact match — try user-configured fallback chain + if (_config != null) + { + var userFallbacks = _config.GetFallbacks(fontName); + if (userFallbacks != null) + { + var resolved = TryResolveFromChain(userFallbacks, subFamily); + if (resolved != null) + return resolved; + } + } + + // 4. Try built-in fallback chain for known Office/system fonts. + // Runs after user config so user preferences win, but still provides a metric-aware + // safety net for fonts the user hasn't configured. + var builtinFallbacks = BuiltinFontFallbackChains.GetFallbacks(fontName); + if (builtinFallbacks != null) + { + var resolved = TryResolveFromChain(builtinFallbacks, subFamily); + if (resolved != null) + return resolved; + } + + // 5. No match found — fall back to built-in Archivo Narrow. + // Only applies when using DefaultFontResolver (i.e. no custom resolver installed). + return EmbeddedFonts.LoadArchivoNarrow(subFamily).RawData; + } + + /// + /// Attempts to resolve a font by walking through a chain of fallback names. + /// Returns the bytes of the first chain entry that produces an exact match, or null if + /// no entry resolves. Each entry is required to match the requested subFamily — falling + /// back from a Bold request to a Regular face would defeat the purpose of fallback. + /// + private byte[] TryResolveFromChain(IEnumerable chain, FontSubFamily subFamily) + { + foreach (var fallbackName in chain) + { + var fallbackFace = _scanner.FindBestMatch( + _fontDirectories, fallbackName, subFamily, _searchSystemDirectories); + + if (fallbackFace != null && fallbackFace.IsExactMatch) + return _fileReader.ReadFontBytes(fallbackFace); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontSerializationContext.cs b/src/EPPlus.Fonts.OpenType/FontSerializationContext.cs new file mode 100644 index 0000000000..a5dc5171ec --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontSerializationContext.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType +{ + public class FontSerializationContext + { + public OpenTypeFont Font { get; } + public bool IsSubsetInProgress { get; } = false; + + public FontSerializationContext(OpenTypeFont font, bool isSubsetInProgress = false) + { + Font = font; + IsSubsetInProgress = isSubsetInProgress; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontSubsetManager.cs b/src/EPPlus.Fonts.OpenType/FontSubsetManager.cs new file mode 100644 index 0000000000..641933d282 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontSubsetManager.cs @@ -0,0 +1,145 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/25/2026 EPPlus Software AB Font subset manager for PDF export + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Prepares subsetted fonts for PDF export by pre-scanning text, + /// distributing code points to the correct font via the fallback chain, + /// and creating minimal subsets of all fonts (including fallbacks). + /// + /// Usage: + /// 1. Create with an IFontProvider (e.g., DefaultFontProvider) + /// 2. Call AddText() for all text that will be rendered (e.g., all cell values) + /// 3. Call CreateSubsettedProvider() to get a new IFontProvider with subsetted fonts + /// 4. Use the returned provider for shaping and PDF rendering + /// + public class FontSubsetManager + { + private readonly IFontProvider _sourceProvider; + + // Code points collected per font (key = original font instance) + private readonly Dictionary> _codePointsByFont = + new Dictionary>(); + + public FontSubsetManager(IFontProvider sourceProvider) + { + if (sourceProvider == null) + throw new ArgumentNullException("sourceProvider"); + + _sourceProvider = sourceProvider; + } + + public FontSubsetManager(OpenTypeFontEngine engine, OpenTypeFont font) + : this(new DefaultFontProvider(engine, font)) + { + + } + + /// + /// Scans text and distributes each code point to the font that will render it. + /// Call this for every piece of text that will appear in the document. + /// + public void AddText(string text) + { + if (string.IsNullOrEmpty(text)) + return; + + var codePoints = CodePointUtil.ExtractCodePoints(text); + + foreach (var cp in codePoints) + { + OpenTypeFont font; + ushort glyphId; + _sourceProvider.TryGetGlyphFont((uint)cp, out font, out glyphId); + + //var fontName = font?.NameTable?.GetFullFontName() ?? "null"; + //if ((char)cp == 'E' || (char)cp == 'P') + //{ + // Console.WriteLine($"[FontSubsetManager.AddText] cp='{(char)cp}' (U+{cp:X4}) -> font='{fontName}', glyphId={glyphId}"); + //} + + HashSet fontCodePoints; + if (!_codePointsByFont.TryGetValue(font, out fontCodePoints)) + { + fontCodePoints = new HashSet(); + _codePointsByFont[font] = fontCodePoints; + } + + fontCodePoints.Add(cp); + } + } + + /// + /// Creates a new IFontProvider where all fonts (primary + fallbacks) are subsetted + /// to contain only the glyphs needed for the collected text. + /// Fonts that had no text collected are excluded from the result. + /// + public IFontProvider CreateSubsettedProvider() + { + var primaryFont = _sourceProvider.PrimaryFont; + var allFonts = _sourceProvider.GetAllFonts().ToList(); + + // Subset each font that has collected code points + var subsetMap = new Dictionary(); + + foreach (var kvp in _codePointsByFont) + { + var originalFont = kvp.Key; + var codePoints = kvp.Value; + + if (codePoints.Count == 0) + continue; + + try + { + var chars = CodePointUtil.CodePointsToString(codePoints); + var subset = originalFont.CreateSubset(chars); + subsetMap[originalFont] = subset; + } + catch (Exception ex) + { + // If subsetting fails, use the original font + System.Diagnostics.Debug.WriteLine( + $"Warning: Could not subset '{originalFont.NameTable?.GetFullFontName()}': {ex.Message}"); + subsetMap[originalFont] = originalFont; + } + } + + // Build new provider with subsetted fonts, preserving fallback order + var subsetPrimary = subsetMap.ContainsKey(primaryFont) + ? subsetMap[primaryFont] + : primaryFont; + + var provider = new CustomFontProvider(subsetPrimary); + + // Add fallback fonts in their original order (skip primary) + for (int i = 1; i < allFonts.Count; i++) + { + var originalFallback = allFonts[i]; + + if (subsetMap.ContainsKey(originalFallback)) + { + provider.AddFallback(subsetMap[originalFallback]); + } + // If no code points were collected for this fallback, skip it entirely + } + + return provider; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontTableReaderFactory.cs b/src/EPPlus.Fonts.OpenType/FontTableReaderFactory.cs new file mode 100644 index 0000000000..1e7bf4162f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontTableReaderFactory.cs @@ -0,0 +1,41 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; + +namespace EPPlus.Fonts.OpenType +{ + internal class FontTableReaderFactory + { + public FontTableReaderFactory(byte[] fontBytes) + { + _fontBytes = fontBytes ?? throw new ArgumentNullException(nameof(fontBytes)); + } + + private readonly byte[] _fontBytes; + + public int FontBytesLength => _fontBytes?.Length ?? 0; + + public FontsBinaryReader CreateReader(long baseOffset = 0) + { + if (baseOffset == -1) baseOffset = 0; + // Validate and clamp baseOffset + if (baseOffset < 0 || baseOffset > _fontBytes.Length) + throw new ArgumentOutOfRangeException("baseOffset", "Offset is outside of the font buffer."); + + var ms = new MemoryStream(_fontBytes); + ms.Position = baseOffset; + return new FontsBinaryReader(ms); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationContext.cs b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationContext.cs new file mode 100644 index 0000000000..e7349e30ae --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationContext.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.FontValidation +{ + public class FontValidationContext + { + private readonly OpenTypeFont _font; + public FontValidationContext(OpenTypeFont font) + { + _font = font; + } + + public OpenTypeFont Font { get { return _font; } } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationMessage.cs b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationMessage.cs new file mode 100644 index 0000000000..73ad07172b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationMessage.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + [DebuggerDisplay("Severity = {Severity}, Messages={Message}")] + public class FontValidationMessage + { + + public TableValidationResult ParentResult { get; private set; } + + public FontValidationSeverity Severity { get; } + public string Message { get; } + + public FontValidationMessage(TableValidationResult parentResult, FontValidationSeverity severity, string message) + { + Severity = severity; + Message = message; + ParentResult = parentResult; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationReport.cs b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationReport.cs new file mode 100644 index 0000000000..d8b80b092e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationReport.cs @@ -0,0 +1,161 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + [DebuggerDisplay("IsValid = {IsValid}, Errors = {ErrorCount}, Warnings = {WarningCount}, Tables = {Results.Count}")] + public class FontValidationReport + { + private readonly List _results = new List(); + + public IList Results + { + get { return _results; } + } + + public bool IsValid + { + get + { + foreach (var r in _results) + { + if (!r.IsValid) return false; + } + return true; + } + } + + // ✅ NYA PROPERTIES + + /// + /// Gets all error messages from all tables + /// + public IEnumerable Errors + { + get + { + foreach (var result in _results) + { + foreach (var error in result.Errors) + { + yield return error; + } + } + } + } + + /// + /// Gets all warning messages from all tables + /// + public IEnumerable Warnings + { + get + { + foreach (var result in _results) + { + foreach (var warning in result.Warnings) + { + yield return warning; + } + } + } + } + + /// + /// Gets all information messages from all tables + /// + public IEnumerable Information + { + get + { + foreach (var result in _results) + { + foreach (var info in result.Information) + { + yield return info; + } + } + } + } + + /// + /// Gets total count of errors across all tables + /// + public int ErrorCount + { + get + { + int count = 0; + foreach (var result in _results) + { + foreach (var msg in result.Messages) + { + if (msg.Severity == FontValidationSeverity.Error) + count++; + } + } + return count; + } + } + + /// + /// Gets total count of warnings across all tables + /// + public int WarningCount + { + get + { + int count = 0; + foreach (var result in _results) + { + foreach (var msg in result.Messages) + { + if (msg.Severity == FontValidationSeverity.Warning) + count++; + } + } + return count; + } + } + + public void AddResult(TableValidationResult result) + { + _results.Add(result); + } + + public void AddMessage(FontValidationSeverity severity, string message) + { + TableValidationResult globalResult = new TableValidationResult(); + globalResult.TableName = "Font"; + globalResult.AddMessage(severity, message); + _results.Add(globalResult); + } + + public string FormatSummary() + { + var sb = new System.Text.StringBuilder(); + sb.AppendLine("Font Validation Summary:"); + foreach (var r in _results) + { + sb.AppendLine("[" + r.TableName + "] " + (r.IsValid ? "Valid" : "Invalid")); + foreach (var msg in r.Messages) + { + sb.AppendLine(msg.ToString()); + } + } + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationSeverity.cs b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationSeverity.cs new file mode 100644 index 0000000000..b9d90baf27 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidationSeverity.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + [Flags] + public enum FontValidationSeverity + { + Error = 1, + Warning = 2, + Information = 4, + All = Error | Warning | Information + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/FontValidator.cs b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidator.cs new file mode 100644 index 0000000000..7cf55db17d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/FontValidator.cs @@ -0,0 +1,141 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Tables; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Hhea; +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using EPPlus.Fonts.OpenType.Tables.Name; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.Tables.Post; +using EPPlus.Fonts.OpenType.Tables.Vhea; +using EPPlus.Fonts.OpenType.Tables.Vmtx; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + public class FontValidator + { + private readonly List _validators; + private readonly Dictionary> _tableAccessors; + + public FontValidator() + { + _validators = new List(); + _tableAccessors = new Dictionary>(); + + // Register validators + _validators.Add(new HeadTableValidator()); + _validators.Add(new MaxpTableValidator()); + _validators.Add(new HheaTableValidator()); + _validators.Add(new VheaTableValidator()); + _validators.Add(new NameTableValidator()); + _validators.Add(new Os2TableValidator()); + _validators.Add(new PostTableValidator()); + _validators.Add(new CmapTableValidator()); + _validators.Add(new LocaTableValidator()); + _validators.Add(new HmtxTableValidator()); + _validators.Add(new VmtxTableValidator()); + _validators.Add(new GlyfTableValidator()); + _validators.Add(new GsubTableValidator()); + // Add more as needed... + + // Register table accessors + _tableAccessors.Add(typeof(HeadTable), delegate(OpenTypeFont font) { return font.HeadTable; }); + _tableAccessors.Add(typeof(MaxpTable), delegate(OpenTypeFont font) { return font.MaxpTable; }); + _tableAccessors.Add(typeof(HheaTable), delegate(OpenTypeFont font) { return font.HheaTable; }); + _tableAccessors.Add(typeof(VheaTable), delegate (OpenTypeFont font) { return font.VheaTable; }); + _tableAccessors.Add(typeof(NameTable), delegate(OpenTypeFont font) { return font.NameTable; }); + _tableAccessors.Add(typeof(Os2Table), delegate(OpenTypeFont font) { return font.Os2Table; }); + _tableAccessors.Add(typeof(PostTable), delegate (OpenTypeFont font) { return font.PostTable; }); + _tableAccessors.Add(typeof(CmapTable), delegate (OpenTypeFont font) { return font.CmapTable; }); + _tableAccessors.Add(typeof(LocaTable), delegate (OpenTypeFont font) { return font.LocaTable; }); + _tableAccessors.Add(typeof(HmtxTable), delegate (OpenTypeFont font) { return font.HmtxTable; }); + _tableAccessors.Add(typeof(VmtxTable), delegate (OpenTypeFont font) { return font.VmtxTable; }); + _tableAccessors.Add(typeof(GlyfTable), delegate (OpenTypeFont font) { return font.GlyfTable; }); + _tableAccessors.Add(typeof(GsubTable), delegate (OpenTypeFont font) { return font.GsubTable; }); + } + + public FontValidationReport Validate(OpenTypeFont font, FontValidationSeverity logLevel = FontValidationSeverity.All) + { + FontValidationReport report = new FontValidationReport(); + FontValidationContext context = new FontValidationContext(font); + + // Validates Offset subtable + var offsetValidator = new OffsetSubtableValidator(); + var osResult = offsetValidator.Validate(font, context, logLevel); + report.AddResult(osResult); + + // Validate table records first + var tableRecordsValidator = new TableRecordsValidator(); + var trResult = tableRecordsValidator.Validate(font, context, logLevel); + report.AddResult(trResult); + + // Validate each registered table + for (int i = 0; i < _validators.Count; i++) + { + ITableValidator validator = _validators[i]; + validator.LogLevel = logLevel; + Func accessor; + + if (!_tableAccessors.TryGetValue(validator.TableType, out accessor)) + { + report.AddMessage(FontValidationSeverity.Warning, + "No accessor registered for table " + validator.TableName + "."); + continue; + } + + FontTableBase table = accessor(font); + + if (table == null) + { + FontValidationSeverity severity = validator.TableType != null && table == null + ? FontValidationSeverity.Warning + : FontValidationSeverity.Error; + + // Use IsEssentialTable property for severity + if (validator.TableType != null && table == null) + { + severity = FontValidationSeverity.Warning; + } + + report.AddMessage(table != null && table.IsEssentialTable + ? FontValidationSeverity.Error + : FontValidationSeverity.Warning, + "Table " + validator.TableName + " is missing."); + continue; + } + + // Validate table + TableValidationResult result = validator.Validate(table, context); + if (result != null) + { + report.AddResult(result); + } + else + { + report.AddMessage(FontValidationSeverity.Error, + "Validator for " + validator.TableName + " returned null result."); + } + } + + return report; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/ITableValidator.cs b/src/EPPlus.Fonts.OpenType/FontValidation/ITableValidator.cs new file mode 100644 index 0000000000..368370b0bc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/ITableValidator.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + public interface ITableValidator + { + // Target table type + Type TableType { get; } + + // Human-readable table name + string TableName { get; } + + FontValidationSeverity LogLevel { get; set; } + + // Non-generic validate for dispatcher + TableValidationResult Validate(FontTableBase table, FontValidationContext context); + } + + // Generic version for validator implementations + public interface ITableValidator : ITableValidator where T : FontTableBase + { + TableValidationResult Validate(T table, FontValidationContext context); + } + +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTime.cs b/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTime.cs new file mode 100644 index 0000000000..bc2a123304 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTime.cs @@ -0,0 +1,45 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + internal static class LongDateTime + { + // OpenType epoch: 1904-01-01 00:00:00 UTC + private static readonly DateTime EpochUtc = new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// Converts OpenType LONGDATETIME (seconds since 1904-01-01 UTC) to DateTime (UTC). + /// Returns null if value is obviously invalid (e.g., less than MinValue or overflow). + /// + public static DateTime? ToDateTimeUtc(long secondsSinceEpoch) + { + try + { + // Guard against clearly invalid negatives far before epoch (spec says seconds since epoch; negatives are unusual) + // We allow 0 (exact epoch) and positive values; small negatives can be treated as invalid. + if (secondsSinceEpoch < 0) + return null; + + // AddSeconds internally checks for overflow; we use checked for safety. + DateTime dt = EpochUtc.AddSeconds(secondsSinceEpoch); + return dt; + } + catch + { + return null; + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTimeLimites.cs b/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTimeLimites.cs new file mode 100644 index 0000000000..a1c127b4eb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/LongDateTimeLimites.cs @@ -0,0 +1,36 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + + internal static class LongDateTimeLimits + { + // Epoch + private static readonly DateTime EpochUtc = new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + // Precompute boundaries in seconds since epoch + public static readonly long MinSeconds = 0L; // 1904-01-01 + public static long MaxSeconds // now + 10 years + { + get + { + DateTime max = DateTime.UtcNow.AddYears(10); + TimeSpan span = max - EpochUtc; + return (long)span.TotalSeconds; + } + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/OffsetSubtableValidator.cs b/src/EPPlus.Fonts.OpenType/FontValidation/OffsetSubtableValidator.cs new file mode 100644 index 0000000000..e86e3e9747 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/OffsetSubtableValidator.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + internal class OffsetSubtableValidator + { + public FontValidationSeverity LogLevel { get; set; } = FontValidationSeverity.All; + + public TableValidationResult Validate(OpenTypeFont font, FontValidationContext context, FontValidationSeverity logLevel) + { + var result = new TableValidationResult { TableName = "OffsetSubtable", LogLevel = logLevel }; + + // Läs värden + ushort numTables = font.NumTables; + ushort searchRange = font.SearchRange; + ushort entrySelector = font.EntrySelector; + ushort rangeShift = font.RangeShift; + + // Beräkna förväntade värden + int maxPower = (int)Math.Pow(2, (int)Math.Floor(Math.Log(numTables, 2))); + ushort expectedSearchRange = (ushort)(maxPower * 16); + ushort expectedEntrySelector = (ushort)Math.Floor(Math.Log(numTables, 2)); + ushort expectedRangeShift = (ushort)((numTables * 16) - expectedSearchRange); + + // Validera + if (searchRange != expectedSearchRange) + result.AddMessage(FontValidationSeverity.Error, $"searchRange mismatch: expected {expectedSearchRange}, got {searchRange}."); + if (entrySelector != expectedEntrySelector) + result.AddMessage(FontValidationSeverity.Error, $"entrySelector mismatch: expected {expectedEntrySelector}, got {entrySelector}."); + if (rangeShift != expectedRangeShift) + result.AddMessage(FontValidationSeverity.Error, $"rangeShift mismatch: expected {expectedRangeShift}, got {rangeShift}."); + + return result; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/TableRecordsValidator.cs b/src/EPPlus.Fonts.OpenType/FontValidation/TableRecordsValidator.cs new file mode 100644 index 0000000000..ba488ebb69 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/TableRecordsValidator.cs @@ -0,0 +1,183 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 12/22/2025 EPPlus Software AB Support in-memory fonts (subsets) + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Utils; +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + internal class TableRecordsValidator + { + public TableValidationResult Validate(OpenTypeFont font, FontValidationContext context, FontValidationSeverity logLevel) + { + var result = new TableValidationResult { TableName = "TableRecords", LogLevel = logLevel }; + + var records = font.TableRecords; + if (records == null || records.Count == 0) + { + result.AddMessage(FontValidationSeverity.Error, "No table records found."); + return result; + } + + // Get file length - either from font property or calculate from table records + long fileLength = font.FileLength; + + // If fileLength is not available (in-memory fonts like subsets), calculate it + if (fileLength <= 0) + { + fileLength = CalculateFileLengthFromTableRecords(records); + + if (fileLength <= 0) + { + result.AddMessage(FontValidationSeverity.Error, "Font file length could not be determined or is zero."); + } + } + + foreach (var kvp in records) + { + string tag = kvp.Key; + TableRecord record = kvp.Value; + + // Rule 1: Tag must be 4 chars + if (tag == null || tag.Length != 4) + { + result.AddMessage(FontValidationSeverity.Error, + $"Invalid tag '{tag}'. Expected 4 characters."); + } + + // Rule 2: Offset and Length must be > 0 + if (record.Offset == 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"Offset for tag '{tag}' is 0."); + } + if (record.Length == 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"Length for tag '{tag}' is 0."); + } + + // Rule 3: Offset must be aligned to 4-byte boundary + if ((record.Offset & 0x3u) != 0u) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Offset for tag '{tag}' ({record.Offset}) is not 4-byte aligned."); + } + + // Rule 4: Offset must be within file bounds + if (fileLength > 0) + { + long offset = (long)record.Offset; + long length = (long)record.Length; + + if (offset < 0 || offset >= fileLength) + { + result.AddMessage(FontValidationSeverity.Error, + $"Offset for tag '{tag}' ({record.Offset}) is outside font file (length {fileLength})."); + } + + long end = offset + length; + if (end < 0 || end > fileLength) + { + result.AddMessage(FontValidationSeverity.Error, + $"Table '{tag}' exceeds file bounds: offset {record.Offset} + length {record.Length} = {end}, file length {fileLength}."); + } + } + + // Rule 5: Validate checksum using ChecksumCalculator + var tableData = font.GetTableData(tag); + if (tableData != null && tableData.Length > 0) + { + uint calculatedChecksum = ChecksumCalculator.CalculateTableChecksum(tableData, tag); + if (calculatedChecksum != record.Checksum) + { + result.AddMessage(FontValidationSeverity.Error, + $"Checksum mismatch for table '{tag}': expected {record.Checksum}, got {calculatedChecksum}."); + } + } + else + { + result.AddMessage(FontValidationSeverity.Warning, + $"Could not read data for table '{tag}' to validate checksum."); + } + } + + // Validate font-level checksum adjustment + var headTable = font.HeadTable; + if (headTable != null) + { + if (font.RawData != null) + { + // Validate checksum only for fonts loaded from disk/stream + byte[] fontData = (byte[])font.RawData.Clone(); + int adjustmentOffset = (int)records["head"].Offset + 8; + for (int i = 0; i < 4; i++) fontData[adjustmentOffset + i] = 0; + uint sum = ChecksumCalculator.CalculateFontChecksum(fontData); + uint expectedAdjustment = 0xB1B0AFBA - sum; + if (expectedAdjustment != headTable.ChecksumAdjustment) + { + result.AddMessage(FontValidationSeverity.Error, + $"Font checksum adjustment failed: expected {expectedAdjustment:X8}, got {headTable.ChecksumAdjustment:X8}."); + } + } + else + { + // RawData not available (subset font or constructed in-memory) + // Skip checksum validation + result.AddMessage(FontValidationSeverity.Information, + "Skipping font checksum validation - raw data not available (in-memory font)."); + } + } + else + { + result.AddMessage(FontValidationSeverity.Warning, "Head table missing, cannot validate font checksum adjustment."); + } + + return result; + } + + /// + /// Calculates the expected file length from table records. + /// Used for in-memory fonts (subsets) that don't have an underlying stream. + /// + private long CalculateFileLengthFromTableRecords(System.Collections.Generic.IDictionary records) + { + if (records == null || records.Count == 0) + return 0; + + long maxEnd = 0; + + // Find the highest offset + length + foreach (var record in records.Values) + { + long tableEnd = (long)record.Offset + (long)record.Length; + if (tableEnd > maxEnd) + { + maxEnd = tableEnd; + } + } + + // Ensure we account for the header + // Header = 12 bytes (sfnt version + offsets) + 16 bytes per table record + long headerSize = 12 + (records.Count * 16); + + if (headerSize > maxEnd) + { + maxEnd = headerSize; + } + + return maxEnd; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/TableValidationResult.cs b/src/EPPlus.Fonts.OpenType/FontValidation/TableValidationResult.cs new file mode 100644 index 0000000000..283802c28c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/TableValidationResult.cs @@ -0,0 +1,47 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + [DebuggerDisplay("IsValid = {IsValid}, Table = {TableName}, #Messages={MessageCount}")] + public class TableValidationResult + { + private readonly List _messages = new List(); + + public string TableName { get; set; } + + public FontValidationSeverity LogLevel { get; set; } = FontValidationSeverity.All; + + public IEnumerable Messages => _messages; + + public int MessageCount => _messages.Count; + + public bool IsValid => !_messages.Any(m => m.Severity == FontValidationSeverity.Error); + + public void AddMessage(FontValidationSeverity severity, string message) + { + if((LogLevel & severity) != 0) + { + _messages.Add(new FontValidationMessage(this, severity, message)); + } + } + + public IEnumerable Errors => _messages.Where(m => m.Severity == FontValidationSeverity.Error); + public IEnumerable Warnings => _messages.Where(m => m.Severity == FontValidationSeverity.Warning); + public IEnumerable Information => _messages.Where(m => m.Severity == FontValidationSeverity.Information); + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontValidation/TableValidatorBase.cs b/src/EPPlus.Fonts.OpenType/FontValidation/TableValidatorBase.cs new file mode 100644 index 0000000000..96c87c0e27 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontValidation/TableValidatorBase.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; +using System; + +namespace EPPlus.Fonts.OpenType.FontValidation +{ + internal abstract class TableValidatorBase : ITableValidator + where T : FontTableBase + { + public abstract Type TableType { get; } + public abstract string TableName { get; } + + public FontValidationSeverity LogLevel { get; set; } = FontValidationSeverity.All; + + public abstract TableValidationResult Validate(T table, FontValidationContext context); + + TableValidationResult ITableValidator.Validate(FontTableBase table, FontValidationContext context) + => Validate((T)table, context); + + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontsBinaryReader.cs b/src/EPPlus.Fonts.OpenType/FontsBinaryReader.cs new file mode 100644 index 0000000000..1f07244a06 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontsBinaryReader.cs @@ -0,0 +1,93 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; + +namespace EPPlus.Fonts.OpenType +{ + internal class FontsBinaryReader : BinaryReader + { + public FontsBinaryReader(Stream input) : base(input) + { + } + + + private string _context; + private int _numberOfReadBytes = 0; + + + internal void SetContext(string name) + { + _context = name; + _numberOfReadBytes = 0; + } + + internal ushort ReadUInt16BigEndian() + { + var b = ReadBytes(2); + return BitConverter.ToUInt16(new byte[] { b[1], b[0] }, 0); + } + internal short ReadInt16BigEndian() + { + var b = ReadBytes(2); + return BitConverter.ToInt16(new byte[] { b[1], b[0] }, 0); + } + + internal uint ReadUInt24BigEndian() + { + var b = ReadBytes(3); + return (uint)((b[0] << 16) | (b[1] << 8) | b[2]); + } + + + internal int ReadInt32BigEndian() + { + var b = ReadBytes(4); + return BitConverter.ToInt32(new byte[] { b[3], b[2], b[1], b[0] }, 0); + } + + internal uint ReadUInt32BigEndian() + { + var b = ReadBytes(4); + return BitConverter.ToUInt32(new byte[] { b[3], b[2], b[1], b[0] }, 0); + } + + internal long ReadInt64BigEndian() + { + var b = ReadBytes(8); + return BitConverter.ToInt64(new byte[] { b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0] }, 0); + } + + + internal ushort[] ReadUInt16ArrayBigEndian(int count) + { + var result = new ushort[count]; + for (int i = 0; i < count; i++) + { + result[i] = ReadUInt16BigEndian(); + } + return result; + } + + internal short[] ReadInt16ArrayBigEndian(int count) + { + var result = new short[count]; + for (int i = 0; i < count; i++) + { + result[i] = ReadInt16BigEndian(); + } + return result; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/FontsBinaryWriter.cs b/src/EPPlus.Fonts.OpenType/FontsBinaryWriter.cs new file mode 100644 index 0000000000..1d7582469f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/FontsBinaryWriter.cs @@ -0,0 +1,136 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; + +namespace EPPlus.Fonts.OpenType +{ + internal class FontsBinaryWriter : BinaryWriter + { + + internal FontsBinaryWriter(Stream output) : base(output) + { + } + + private int _bytesWritten = 0; + private bool _hit = false; + + private void IncreaseBytesWritten(int nBytes) + { + _bytesWritten += nBytes; + if(_bytesWritten >= 6320 && !_hit) + { + _hit = true; + } + } + + internal void WriteUInt16BigEndian(ushort value) + { + var bytes = BitConverter.GetBytes(value); + Write(bytes[1]); // MSB + Write(bytes[0]); // LSB + } + + internal void WriteInt16BigEndian(short value) + { + var bytes = BitConverter.GetBytes(value); + Write(bytes[1]); + Write(bytes[0]); + } + + + internal void WriteUInt24BigEndian(uint value) + { + if (value > 0xFFFFFF) + throw new ArgumentOutOfRangeException(nameof(value), "Value exceeds 24-bit range."); + + var bytes = BitConverter.GetBytes(value); + Write(bytes[2]); // high byte + Write(bytes[1]); // mid byte + Write(bytes[0]); // low byte + } + + + internal void WriteUInt32BigEndian(uint value) + { + var bytes = BitConverter.GetBytes(value); + Write(bytes[3]); + Write(bytes[2]); + Write(bytes[1]); + Write(bytes[0]); + } + + internal void WriteInt32BigEndian(int value) + { + var bytes = BitConverter.GetBytes(value); + Write(bytes[3]); + Write(bytes[2]); + Write(bytes[1]); + Write(bytes[0]); + } + + internal void WriteInt64BigEndian(long value) + { + var bytes = BitConverter.GetBytes(value); + Write(bytes[7]); + Write(bytes[6]); + Write(bytes[5]); + Write(bytes[4]); + Write(bytes[3]); + Write(bytes[2]); + Write(bytes[1]); + Write(bytes[0]); + } + + public override void Write(byte[] buffer) + { + base.Write(buffer); + IncreaseBytesWritten(buffer.Length); + } + + public override void Write(byte value) + { + base.Write(value); + IncreaseBytesWritten(1); + } + + public override void Write(int i) + { + base.Write(i); + IncreaseBytesWritten(4); + } + + public override void Write(uint i) + { + base.Write(i); + IncreaseBytesWritten(4); + } + + public override void Write(ushort value) + { + base.Write(value); + IncreaseBytesWritten(2); + } + + public override void Write(short value) + { + base.Write(value); + IncreaseBytesWritten(2); + } + + internal void WriteTag(Tag featureTag) + { + featureTag.Serialize(this); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/IFontProvider.cs b/src/EPPlus.Fonts.OpenType/IFontProvider.cs new file mode 100644 index 0000000000..80a772186d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/IFontProvider.cs @@ -0,0 +1,43 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Provides fonts for text shaping with fallback support. + /// + public interface IFontProvider + { + /// + /// Gets the primary font (user's chosen font). + /// + OpenTypeFont PrimaryFont { get; } + + /// + /// Tries to find a font that contains the specified code point. + /// Searches primary font first, then fallbacks. + /// + /// Unicode code point + /// The font containing the glyph + /// The glyph ID in that font + /// True if a font was found that contains the glyph + bool TryGetGlyphFont(uint codePoint, out OpenTypeFont font, out ushort glyphId); + + /// + /// Gets all fonts in the provider (primary + fallbacks). + /// Used for subsetting and PDF embedding. + /// + IEnumerable GetAllFonts(); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Integration/CharacterType.cs b/src/EPPlus.Fonts.OpenType/Integration/CharacterType.cs new file mode 100644 index 0000000000..26ea977be0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/CharacterType.cs @@ -0,0 +1,21 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Integration +{ + internal enum CharacterType + { + Space, + EndOfText, + Regular + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/CharInfo.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/CharInfo.cs new file mode 100644 index 0000000000..7169fb7e87 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/CharInfo.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace EPPlus.Fonts.OpenType.Integration +{ + //Leaving this for now. May be neccesary for vertical text + public class CharInfo + { + /// + /// Index within AllText + /// + internal int Index; + /// + /// The input Fragment Index + /// + internal int Fragment; + /// + /// The input char index within the fragment + /// + internal int InnerIndex; + /// + /// Width in points of the char + /// + internal double Width; + + internal int Line; + + internal bool IsSeparator { get; set; } + + public CharInfo(int index, int fragment, int fragCharIdx/*, int line*/) + { + Index = index; + Fragment = fragment; + InnerIndex = fragCharIdx; + //Line = line; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/FontFormatBase.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/FontFormatBase.cs new file mode 100644 index 0000000000..e0f4814102 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/FontFormatBase.cs @@ -0,0 +1,79 @@ +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration.DataHolders +{ + public class FontFormatBase : IFontFormatBase + { + public virtual string Family { get; set; } = "Archivo Narrow"; + public virtual FontSubFamily SubFamily { get; set; } = FontSubFamily.Regular; + public virtual float Size { get; set; } = 11f; + + public FontFormatBase(string fontFamily, FontSubFamily subFamily, float fontSize) + { + Family = fontFamily; + SubFamily = subFamily; + Size = fontSize; + } + public FontFormatBase() { } + + /// + /// Legacy constructor. Prefer to avoid with new implementations. To be removed after refactor + /// + /// + public FontFormatBase(MeasurementFont font) + { + Family = font.FontFamily; + SubFamily = GetFontSubFamily(font.Style); + Size = font.Size; + } + + /// + /// Utility for Legacy constructor. Prefer to avoid with new implementations. To be removed after refactor + /// + /// + /// + public static FontSubFamily GetFontSubFamily(MeasurementFontStyles style) + { + if ((style & (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) == + (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) + { + return FontSubFamily.BoldItalic; + } + else if ((style & MeasurementFontStyles.Bold) == MeasurementFontStyles.Bold) + { + return FontSubFamily.Bold; + } + else if ((style & MeasurementFontStyles.Italic) == MeasurementFontStyles.Italic) + { + return FontSubFamily.Italic; + } + + return FontSubFamily.Regular; + } + + public void SetFont(IFontFormatBase font) + { + Family = font.Family; + Size = font.Size; + SubFamily = font.SubFamily; + } + + /// + /// Legacy import + /// + /// + public void SetFont(MeasurementFont font) + { + Family = font.FontFamily; + Size = font.Size; + SubFamily = GetFontSubFamily(font.Style); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/IRichTextFormatSimple.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/IRichTextFormatSimple.cs new file mode 100644 index 0000000000..9d84d24ec1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/IRichTextFormatSimple.cs @@ -0,0 +1,36 @@ +using OfficeOpenXml.Interfaces.RichText; +using System.Drawing; + + +namespace EPPlus.Fonts.OpenType.Integration.DataHolders +{ + /// + /// TODO: Move this to interfaces. Only here in order to not break existing references in PDF + /// + /// Interface for pdf/svg/future richtext users to unify richtext styling + /// + public interface IRichTextFormatSimple : IRichTextFormatEssential + { + bool SubScript { get; set; } + bool SuperScript { get; set; } + + /// + /// Represents value in enum OfficeOpenXml.Style.eUnderlineType + /// + int UnderlineType { get; set; } + /// + /// Represents value in enum OfficeOpenXml.Style.eStrikeType + /// + int StrikeType { get; set; } + + #region potentially remove + /// + /// Represents OfficeOpenXml.Drawing.eTextCapsType + /// + int Capitalization { get; set; } + #endregion + + Color UnderlineColor { get; set; } + public Color FontColor { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextCollectionBase.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextCollectionBase.cs new file mode 100644 index 0000000000..a1c0104f8e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextCollectionBase.cs @@ -0,0 +1,99 @@ +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration.DataHolders +{ + public class RichTextCollectionBase : IRichTextCollection + { + List _list = new List(); + + public IRichTextFormatEssential DefaultRichText = new RichTextFormatSimple(); + + /// + /// Initalizes using hard-coded defaults + /// + public RichTextCollectionBase() : this(new RichTextFormatSimple()) + { + } + + /// + /// Initializes with user supplied defaults + /// + /// Default Fallback Font Options + /// Default RichText Options + public RichTextCollectionBase(IRichTextFormatEssential defaultRichTextOptions) + { + DefaultRichText = defaultRichTextOptions; + } + + public IRichTextFormatEssential this[int index] => _list[index]; + + public string Text + { + get + { + StringBuilder sb = new StringBuilder(); + foreach (var item in _list) + { + sb.Append(item.Text); + } + return sb.ToString(); + } + } + + public int Count => _list.Count; + + public void Add(IRichTextFormatEssential rt) + { + Insert(_list.Count, rt); + } + public IRichTextFormatEssential Insert(int index, IRichTextFormatEssential rt) + { + _list.Insert(index, rt); + return rt; + } + + public IRichTextFormatEssential Add(string Text, bool NewParagraph = false) + { + return Insert(_list.Count, Text, NewParagraph); + } + + public IRichTextFormatEssential Insert(int index, string Text, bool NewParagraph = false) + { + var rt = new RichTextFormatBase(); + rt.Text = Text; + rt.SetFont(DefaultRichText); + _list.Insert(index, rt); + return rt; + } + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + public void Clear() + { + _list.Clear(); + } + + public void RemoveAt(int Index) + { + _list.RemoveAt(Index); + } + + public void Remove(IRichTextFormatEssential Item) + { + _list.Remove(Item); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatBase.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatBase.cs new file mode 100644 index 0000000000..a962186357 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatBase.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Interfaces.Fonts; + +namespace EPPlus.Fonts.OpenType.Integration.DataHolders +{ + /// + /// The most basic rich text format + /// The only properties that belong in this class are those that are absolutely neccesary for Measuring the text correctly + /// + public class RichTextFormatBase : FontFormatBase, IRichTextFormatEssential + { + internal RichTextFormatBase() + { + Italic = false; + Bold = false; + } + + public RichTextFormatBase(string text, string fontFamily, float size, bool bold = false, bool italic = false) + { + Text = text; + Family = fontFamily; + Size = size; + Bold = bold; + Italic = italic; + } + + public string Text { get; set; } + + /// + /// Any inheriting class MUST do this too + /// + public bool Italic + { + get { return (SubFamily & FontSubFamily.Italic) == FontSubFamily.Italic; } + set + { + if (value) + { + //Set Flag + SubFamily = SubFamily | FontSubFamily.Italic; + + } + else + { + //Unset Flag + SubFamily &= ~FontSubFamily.Italic; + } + } + } + + /// + /// Any inheriting class MUST do this too + /// + public bool Bold + { + get { return (SubFamily & FontSubFamily.Bold) == FontSubFamily.Bold; } + set + { + if (value) + { + //Set flag + SubFamily = SubFamily | FontSubFamily.Bold; + + } + else + { + //Unset flag + SubFamily &= ~FontSubFamily.Bold; + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatSimple.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatSimple.cs new file mode 100644 index 0000000000..498c35d4bb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/RichTextFormatSimple.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlus.Fonts.OpenType.Integration.DataHolders +{ + /// + /// Defaults class mainly intended for Cells + /// + public class RichTextFormatSimple : RichTextFormatBase, IRichTextFormatSimple + { + public RichTextFormatSimple() : base() + { + + } + + public RichTextFormatSimple(string text, string fontFamily, float size, bool bold = false, bool italic = false) : base(text, fontFamily, size, bold, italic) + { + + } + + public bool SubScript { get; set; } = false; + + public bool SuperScript { get; set; } = false; + + public int UnderlineType { get; set; } = -1; + + public int StrikeType { get; set; } = -1; + + public int Capitalization { get; set; } = -1; + + public Color UnderlineColor { get; set; } + + public Color FontColor { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextFragmentCollectionSimple.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextFragmentCollectionSimple.cs new file mode 100644 index 0000000000..b85124c837 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextFragmentCollectionSimple.cs @@ -0,0 +1,23 @@ +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +namespace EPPlus.Fonts.OpenType.Integration +{ + public class TextFragmentCollectionSimple : List, IEnumerable + { + public TextFragmentCollectionSimple(List fonts, List texts) : base() + { + for (int i = 0; i< fonts.Count; i++) + { + var tf = new TextFragment() { Text = texts[i] }; + tf.RichTextOptions.SetFont(fonts[i]); + Add(tf); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineCollection.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineCollection.cs new file mode 100644 index 0000000000..4c71afeb63 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineCollection.cs @@ -0,0 +1,335 @@ +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + + + +namespace EPPlus.Fonts.OpenType.Integration +{ + + public class TextLineCollection : List, IEnumerable + { + /// + /// Array of the line numbers where fragment occurs + /// + public List LineFragments = new List(); + List _originalFragments; + + public int[] GetLineNumbersThatUse(TextFragment fragment) + { + var idx = _originalFragments.IndexOf(fragment); + List result = new List(); + if (idx != -1) + { + foreach (var key in fragIdLookup[idx].Keys) + { + result.Add(key); + } + return result.ToArray(); + } + else + { + return null; + } + } + + /// + /// Returns null if fragment is not found in any lines + /// + /// + /// + /// + public List GetTextLinesThatUse(TextFragment fragment) + { + var idx = _originalFragments.IndexOf(fragment); + + if(idx != -1) + { + List retLines = new List(); + foreach (var key in fragIdLookup[idx].Keys) + { + retLines.Add(this[key]); + } + return retLines; + } + else + { + return null; + } + } + /// + /// Returns null if fragment is not found in any linefragments + /// + /// + /// + public List GetInternalLineFragmentsThatUse(TextFragment fragment) + { + var idx = _originalFragments.IndexOf(fragment); + + List retFragments = null; + + if (idx != -1) + { + retFragments = new List(); + + foreach (var key in fragIdLookup[idx].Keys) + { + foreach(var lineFragment in fragIdLookup[idx][key]) + { + retFragments.Add(this[key].InternalLineFragments[lineFragment]); + } + } + } + + return retFragments; + } + + /// + /// Returns null if fragment is not found in any linefragments + /// + /// + /// + public List GetLineFragmentsThatUse(TextFragment fragment) + { + var idx = _originalFragments.IndexOf(fragment); + + List retFragments = null; + + if (idx != -1) + { + retFragments = new List(); + + foreach (var key in fragIdLookup[idx].Keys) + { + foreach (var lineFragment in fragIdLookup[idx][key]) + { + retFragments.Add(this[key].LineFragments[lineFragment]); + } + } + } + + return retFragments; + } + + /// + /// The id of the orginal fragment may correspond to + /// multiple lines with multiple different richtext fragments + /// So. fragIdLookup[fragId] returns dictionary of lines that contains the fragment + /// fragIdLookup[fragId][lineNum] returns list of output fragments that contain the font + /// fragIdLookup[fragId][lineNum][0] returns first richtextfragment within the line that contains the font. + /// + Dictionary>> fragIdLookup = new Dictionary>>(); + + //internal MeasurementFont GetFont(int fragIdx) + //{ + // return _originalFragments[fragIdx].RichTextOptions; + //} + + /// + /// If using this MUST call FinalizeTextLineData to finish the information gathering + /// + /// + public TextLineCollection(TextFragmentCollectionSimple fragmentCollection) + { + _originalFragments = fragmentCollection; + + for (int i = 0; i < fragmentCollection.Count; i++) + { + fragIdLookup.Add(i, new Dictionary>()); + } + } + + public TextLineCollection() + { + + } + + private void AddToDictionary(int idx, int lineNum, int fragPosInline) + { + + if (fragIdLookup[idx].ContainsKey(lineNum) == false) + { + fragIdLookup[idx].Add(lineNum, new List()); + } + + fragIdLookup[idx][lineNum].Add(fragPosInline); + } + + double _descentOfLastLine = -1d; + //Combined descent of previous line and ascent of current line gives the linespacing of that line + internal List LinespacingPerLine = new List(); + /// + /// The total local position of the text baseLine + /// AKA the position of this line offset by all the lines before it. + /// + internal List BaseLinePositions = new List(); + + internal void FinalizeTextLineData(List lines) + { + _descentOfLastLine = 0; + var currentLinePosition = 0d; + + for (int i = 0; i < lines.Count; i++) + { + int lineNum = i; + int fragCount = 0; + + currentLinePosition += lines[i].LargestAscent; + + foreach (var lf in lines[i].InternalLineFragments) + { + var idx = lf.FragmentIndex; + AddToDictionary(idx, lineNum, fragCount); + LineFragmentOutput data; + if (lines[i].LineFragments == null || lines[i].LineFragments.Count != lines[i].InternalLineFragments.Count) + { + data = new LineFragmentOutput( + () => { return _originalFragments[idx]; }, + () => { return lf.Width; }, + () => { return lf.StartIdx; }, + () => { return lf.StartRt; }, + () => { return lf.StartOriginal; }, + lines[i].GetLineFragmentText(lf) + ); + } + else + { + //If already calculate don't duplicate just use the data + data = lines[i].LineFragments[fragCount]; + } + + LineFragments.Add(data); + + fragCount++; + } + + //The linespacing above this line + var lineSpacing = lines[i].LargestAscent + _descentOfLastLine; + lines[i].LineSpacingAbove = lineSpacing; + LinespacingPerLine.Add(lineSpacing); + + //All lines and spacing before it + the ascent of this line + //Gives the current local position + BaseLinePositions.Add(currentLinePosition); + + _descentOfLastLine = lines[i].LargestDescent; + currentLinePosition += _descentOfLastLine; + + Add(lines[i]); + } + } + + public double LargestWidthWithSpace { get; private set; } = -1d; + public double LargestWidthWithoutSpace { get; private set; } = -1d; + public int idxOfLargestLine { get; private set; } = -1; + public List SpaceWidthsPerLine { get; private set; } = new List(); + + public TextLineCollection(List lines, List originalFragments, bool finalizeLineFragments = false) + { + if (finalizeLineFragments) + { + int lineIdx = 0; + foreach (var line in lines) + { + double largestAscent = 0; + double largestDescent = 0; + double largestFontSize = 0; + foreach (var lineFragment in line.InternalLineFragments) + { + var frag = originalFragments[lineFragment.FragmentIndex]; + if (frag == null) continue; + largestAscent = Math.Max(frag.AscentPoints, largestAscent); + largestDescent = Math.Max(frag.DescentPoints, largestDescent); + largestFontSize = Math.Max(largestFontSize, frag.Size); + } + line.LargestAscent = largestAscent; + line.LargestDescent = largestDescent; + line.LargestFontSize = largestFontSize; + + line.FinalizeLineFragments(originalFragments); + + if (line.Width > LargestWidthWithSpace) + { + LargestWidthWithSpace = line.Width; + + } + if (line.GetWidthWithoutTrailingSpaces() > LargestWidthWithoutSpace) + { + LargestWidthWithoutSpace = line.GetWidthWithoutTrailingSpaces(); + idxOfLargestLine = lineIdx; + } + LargestWidthWithSpace = Math.Max(LargestWidthWithSpace, line.Width); + LargestWidthWithoutSpace = Math.Max(LargestWidthWithoutSpace, line.GetWidthWithoutTrailingSpaces()); + SpaceWidthsPerLine.Add(line.LastFontSpaceWidth); + lineIdx++; + } + } + + _originalFragments = originalFragments; + + for(int i = 0; i < originalFragments.Count; i++) + { + fragIdLookup.Add(i, new Dictionary>()); + } + + FinalizeTextLineData(lines); + } + + public double GetBaseLinePosition(int lineIndex, double exactLineSpacing = double.NaN) + { + double position = 0d; + + if (double.IsNaN(exactLineSpacing)) + { + position = BaseLinePositions[lineIndex]; + } + else + { + position = lineIndex+1 * exactLineSpacing; + } + + return position; + } + + public double GetHeightOfCollection(double? lsMultiplier, double exactLineSpacing = double.NaN) + { + double height = 0; + + if(double.IsNaN(exactLineSpacing) && lsMultiplier.HasValue) + { + foreach(var spacing in LinespacingPerLine) + { + height += spacing * lsMultiplier.Value; + } + } + else + { + height = exactLineSpacing * Count; + } + + //Descent of the last line needs to be counted + //The last line has no line under it and thus its descent is not counted here otherwise. + height += _descentOfLastLine; + + return height; + } + + public double GetWidthOfCollection(bool withSpace = false) + { + if(withSpace) + { + return LargestWidthWithSpace; + } + else + { + return LargestWidthWithoutSpace; + } + } + } +} + diff --git a/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineSimple.cs b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineSimple.cs new file mode 100644 index 0000000000..cb578c0e66 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/DataHolders/TextLineSimple.cs @@ -0,0 +1,141 @@ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + [DebuggerDisplay("{Text}")] + public class TextLineSimple + { + /// + /// Internal data for making operations + /// + public List InternalLineFragments { get; set; } = new List(); + + /// + /// External output data for reading + /// + public List LineFragments { get; internal set; } = new List(); + + public string Text { get; internal set; } + /// + /// The largest font size within this line + /// + public double LargestFontSize { get; internal set; } + /// + /// The largest ascent in points within this line + /// (Two differing fonts with the same size can have different ascents) + /// + public double LargestAscent { get; internal set; } + /// + /// The largest descent in points within this line + /// (Two differing fonts with the same size can have different descents) + /// + public double LargestDescent { get; internal set; } + + public double Width { get; internal set; } + + public double LastFontSpaceWidth { get; internal set; } + + /// + /// The combined ascent of this line and the descent of the previous line + /// + public double LineSpacingAbove { get; internal set; } + + internal bool WasWrappedOnSpace = false; + + /// + /// In renderers like Excel the width of trailing spaces + /// MUST be resepected in some cases. + /// In others (e.g. Centering) the spaces width must be ignored + /// + public double GetWidthWithoutTrailingSpaces() + { + var trailingSpaceCount = 0; + + for (int i = Text.Count() - 1; i > 0; i--) + { + if (Text[i] != ' ') + { + break; + } + + trailingSpaceCount++; + } + + if (WasWrappedOnSpace) + { + trailingSpaceCount++; + } + + var widthWithoutTrail = Width - (LastFontSpaceWidth * (trailingSpaceCount)); + return widthWithoutTrail; + } + + public TextLineSimple() + { + } + + internal void FinalizeLineFragments(List originalFragments) + { + LastFontSpaceWidth = InternalLineFragments.Last().SpaceWidth; + + foreach (var lf in InternalLineFragments) + { + LineFragmentOutput data = new LineFragmentOutput( + () => { return originalFragments[lf.FragmentIndex]; }, + () => { return lf.Width; }, + () => { return lf.StartIdx; }, + () => { return lf.StartRt; }, + () => { return lf.StartOriginal; }, + GetLineFragmentText(lf) + ); + LineFragments.Add(data); + } + } + + public string GetLineFragmentText(LineFragment rtFragment) + { + if (InternalLineFragments.Contains(rtFragment) == false) + { + throw new InvalidOperationException($"GetFragmentText failed. Cannot retrieve {rtFragment} since it is not part of this textLine: {this}"); + } + + if (string.IsNullOrEmpty(Text)) + { + return Text; + } + + var startIdx = rtFragment.StartIdx; + + var idxInLst = InternalLineFragments.FindIndex(x => x == rtFragment); + if (idxInLst == InternalLineFragments.Count - 1) + { + return Text.Substring(startIdx, Text.Length - startIdx); + } + else + { + var endIdx = InternalLineFragments[idxInLst + 1].StartIdx; + return Text.Substring(startIdx, endIdx - startIdx); + } + } + + internal LineFragment SplitAndGetLeftoverLineFragment(ref LineFragment origLf, double widthAtSplit, int charsRt, int charsTotal) + { + //If we are splitting a fragment its position in the new line should be 0 + var newLineFragment = new LineFragment(origLf.FragmentIndex, 0, charsRt, charsTotal); + newLineFragment.Width = origLf.Width - widthAtSplit; + + newLineFragment.SpaceWidth = origLf.SpaceWidth; + + origLf.Width = widthAtSplit; + + return newLineFragment; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/LineFragment.cs b/src/EPPlus.Fonts.OpenType/Integration/LineFragment.cs new file mode 100644 index 0000000000..6cf2495f27 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/LineFragment.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// The fragment of a richTextFragment that is within a line + /// + public class LineFragment + { + /// + /// Char idx within the TOTAL of the original input string regardless of what richtext/line + /// + public int StartOriginal { get; internal set; } + + /// + /// Start char position within input richtext fragment + /// + public int StartRt { get; internal set; } + + /// + /// Start char position within TextLineSimple.Text + /// + public int StartIdx { get; set; } + /// + /// Width of this fragment + /// + public double Width { get; set; } + /// + /// Index of original TextFragment + /// + public int FragmentIndex { get; set; } + + /// + /// Width of a space in the original TextFragment + /// + public double SpaceWidth { get; internal set; } + + //public double AscentInPoints { get; private set; } + //public double DescentInPoints { get; private set; } + + internal LineFragment(int rtFragmentIdx, int idxWithinLine, int startIdxRt, int idxOriginal) + { + FragmentIndex = rtFragmentIdx; + StartIdx = idxWithinLine; + StartRt = startIdxRt; + StartOriginal = idxOriginal; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/LineFragmentOutput.cs b/src/EPPlus.Fonts.OpenType/Integration/LineFragmentOutput.cs new file mode 100644 index 0000000000..64334ea432 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/LineFragmentOutput.cs @@ -0,0 +1,75 @@ +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// Finalized output which uses callbacks to get data but can never have data set. + /// + [DebuggerDisplay("{Text}")] + public class LineFragmentOutput + { + /// + /// Char index within the FULL TEXT of all input fragments + /// + public int StartFullTextIdx { get { return _getFullTextIdx(); } } + + /// + /// Char idx within the input fragment + /// + public int StartRtIdx { get { return _getStartIdxRt(); } } + /// + /// Char idx within the line + /// + public int StartIdx { get { return _getStartIdx(); } } + /// + /// Width of this fragment + /// + public double Width { get { return _getWidth(); } } + + /// + /// Text of this fragment + /// Is not a callback since the LineFragment class does not store the string data directly. + /// This is for performance reasons. + /// + public string Text { get; } + + /// + /// Original text fragment + /// If this becomes null/loses its reference the original textfragment has been deleted + /// Don't delete/clear the original textFragment list if you plan to use/check it here. + /// + public ITextFragmentBase OriginalTextFragment { get { return _getTextFragment(); } } + + + /// + /// Looks up the data in the internal class LineFragment instead of making copies + /// + #region Callbacks + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Func _getTextFragment; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Func _getWidth; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Func _getStartIdx; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Func _getStartIdxRt; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Func _getFullTextIdx; + #endregion + + internal LineFragmentOutput(Func getTextFragment, Func getWidth, Func startIdx, Func startRt, Func fullTextIdx, string text) + { + _getTextFragment = getTextFragment; + _getWidth = getWidth; + _getStartIdx = startIdx; + _getStartIdxRt = startRt; + _getFullTextIdx = fullTextIdx; + Text = text; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/OpenTypeFontTextMeasurer.cs b/src/EPPlus.Fonts.OpenType/Integration/OpenTypeFontTextMeasurer.cs new file mode 100644 index 0000000000..1dfa66ebc4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/OpenTypeFontTextMeasurer.cs @@ -0,0 +1,115 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB OpenTypeFontTextMeasurer implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// ITextMeasurer implementation using OpenType font shaping. + /// Provides accurate text measurement with ligatures and kerning support. + /// + public class OpenTypeFontTextMeasurer : ITextMeasurer + { + private readonly ITextShaper _shaper; + private ShapingOptions _shapingOptions; + + public OpenTypeFontTextMeasurer(ITextShaper shaper, ShapingOptions options = null) + { + _shaper = shaper ?? throw new ArgumentNullException(nameof(shaper)); + _shapingOptions = options ?? ShapingOptions.Default; + MeasureWrappedTextCells = true; + } + + /// + /// Always valid - pure .NET implementation with no external dependencies. + /// + public bool ValidForEnvironment() => true; + + /// + /// Controls whether multi-line text (with CR/LF/CRLF) should be measured. + /// + public bool MeasureWrappedTextCells { get; set; } + + /// + /// Measures text width and height. + /// + public TextMeasurement MeasureText(string text, MeasurementFont font) + { + if (string.IsNullOrEmpty(text)) + { + // Return 0x0 for empty string, not TextMeasurement.Empty (-1x-1) + return new TextMeasurement(0, 0); + } + + + // Check if text contains newlines + bool hasNewlines = text.IndexOfAny(new[] { '\r', '\n' }) >= 0; + + if (hasNewlines && MeasureWrappedTextCells) + { + return MeasureMultiLineText(text, font.Size); + } + else + { + return MeasureSingleLineText(text, font.Size); + } + } + + /// + /// Measures a single line of text. + /// + private TextMeasurement MeasureSingleLineText(string text, float fontSize) + { + var shaped = _shaper.Shape(text, _shapingOptions); + + // Convert from design units to points + float width = shaped.GetWidthInPoints(fontSize); + float lineHeight = (float)_shaper.GetLineHeightInPoints(fontSize); + float fontHeight = (float)_shaper.GetFontHeightInPoints(fontSize); + + return new TextMeasurement(width, lineHeight) + { + FontHeight = fontHeight + }; + } + + /// + /// Measures multiple lines of text (separated by CR/LF/CRLF). + /// Returns the maximum width and total height. + /// + private TextMeasurement MeasureMultiLineText(string text, float fontSize) + { + var shapedLines = _shaper.ShapeLines(text, _shapingOptions); + + // Calculate max width across all lines + float maxWidth = 0; + foreach (var line in shapedLines) + { + float lineWidth = line.GetWidthInPoints(fontSize); + maxWidth = Math.Max(maxWidth, lineWidth); + } + + float lineHeight = (float)_shaper.GetLineHeightInPoints(fontSize); + float fontHeight = (float)_shaper.GetFontHeightInPoints(fontSize); + float totalHeight = shapedLines.Length * lineHeight; + + return new TextMeasurement(maxWidth, totalHeight) + { + FontHeight = fontHeight + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Integration/RichText/LayoutSystem.cs b/src/EPPlus.Fonts.OpenType/Integration/RichText/LayoutSystem.cs new file mode 100644 index 0000000000..ae56ef5c7d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/RichText/LayoutSystem.cs @@ -0,0 +1,334 @@ +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Integration.RichText +{ + /// + /// A list of rich-text fragments with relation to eachother + /// Essentially a paragraph handler + /// + public class LayoutSystem + { + /// + /// The Unaltered input fragments + /// + public List InputFragments { get; private set; } + + //The text of the entire paragraph + //regardless of linebreaking or style runs + string FullText; + private List AllChars { get; set; }= new List(); + List SeparatorIndicies = new List(); + List ParagraphSeparatorIndicies = new List(); + List SubParagraphs = new List(); + private List StyleRuns { get; set; } = new List(); + int FullTextLength = 0; + int FullTextLastIdx = 0; + + + TextLineCollection WrappedLineCollection; + private readonly OpenTypeFontEngine _engine; + + public LayoutSystem(OpenTypeFontEngine engine, List preFragments) + : this(engine, preFragments.Cast().ToList()) + { + } + + public LayoutSystem(OpenTypeFontEngine engine, IEnumerable preFragments) + { + if (engine == null) + throw new ArgumentNullException("engine"); + _engine = engine; + + InputFragments = new List(); + foreach (var preFrag in preFragments) + { + var frag = new TextFragmentBase(preFrag); + InputFragments.Add(frag); + } + InitializeLayout(); + } + + public LayoutSystem(OpenTypeFontEngine engine, IEnumerable fragments) + { + if (engine == null) + throw new ArgumentNullException("engine"); + _engine = engine; + + InputFragments = fragments.ToList(); + InitializeLayout(); + } + + private void InitializeLayout() + { + if (InputFragments != null && InputFragments.Count > 0) + { + //Extract basic info about the entire paragraph + InitalizeAllTextAndCharInfo(); + //Split into sub paragraphs + Segmentation(); + + //TODO: Bi-directional analysis (level-runs) these will need to be merged with style runs + + //Segmenting Style Runs (Itimization) + Itemization(); + + //Apply shaping (Scripting and Cluster) in simplest of terms Measure widths/heights of characters in runs + Shaping(); + } + //Line-breaking (Is called by user instead) + //Wrap(); + } + + /// + /// Extract basic info about the entire paragraph + /// + void InitalizeAllTextAndCharInfo() + { + List fragmentStartIdx = new List(); + int allCharIdx = 0; + int fragmentIdx = 0; + foreach (var fragment in InputFragments) + { + int spanIndex = 0; + foreach (var c in fragment.Text) + { + var currCharInfo = new CharInfo(allCharIdx, fragmentIdx, spanIndex); + AllChars.Add(currCharInfo); + if (char.IsSeparator(c)) + { + currCharInfo.IsSeparator = true; + SeparatorIndicies.Add(allCharIdx); + } + + spanIndex++; + allCharIdx++; + } + FullText += fragment.Text; + fragmentIdx++; + } + FullTextLength = allCharIdx; + FullTextLastIdx = FullTextLength - 1; + if(FullTextLength != 0 && FullTextLastIdx == 0) + { + FullTextLastIdx = 1; + } + } + + //Split paragraphs along paragraph separators + void Segmentation() + { + int lastParagraphIdx = 0; + UnicodeCategory category = UnicodeCategory.ParagraphSeparator; + foreach (var sepIdx in SeparatorIndicies) + { + if (CharUnicodeInfo.GetUnicodeCategory(FullText[sepIdx]) == category) + { + ParagraphSeparatorIndicies.Add(sepIdx); + var section = new Paragraph(lastParagraphIdx, sepIdx-1, GetFullText, GetSection); + SubParagraphs.Add(section); + lastParagraphIdx = sepIdx; + } + } + + var lastSection = new Paragraph(lastParagraphIdx, FullTextLength-1, GetFullText, GetSection); + SubParagraphs.Add(lastSection); + } + + /// + /// Seperating input into style-runs + /// + void Itemization() + { + var subParagraphStartIdx = SubParagraphs[0].FullTextStart; + var currIdx = subParagraphStartIdx; + var currFragIdx = 0; + if (AllChars != null && AllChars.Count != 0) + { + currFragIdx = AllChars[0].Fragment; + + var lastRunIdx = 0; + + for (int i = 0; i < SubParagraphs.Count; i++) + { + subParagraphStartIdx = SubParagraphs[i].FullTextStart; + currIdx = subParagraphStartIdx; + + currFragIdx = AllChars[i].Fragment; + + for (int j = 0; j < SubParagraphs[i].Length; j++) + { + currIdx = subParagraphStartIdx + j; + if (AllChars[currIdx].Fragment != currFragIdx) + { + //We have moved one beyond the last char to apply the given style. + //Therefore -1 (unless it is on the very first idx) + var styleRun = new StyleRun(currFragIdx, lastRunIdx, currIdx -1, GetFullText, GetSection); + StyleRuns.Add(styleRun); + //TODO: Technically this should not get its own list it should refer back here + SubParagraphs[i].AddStyleRun(styleRun); + currFragIdx = AllChars[currIdx].Fragment; + lastRunIdx = currIdx; + } + } + + } + + var LastRun = new StyleRun(currFragIdx, lastRunIdx, currIdx, GetFullText, GetSection); + StyleRuns.Add(LastRun); + SubParagraphs[SubParagraphs.Count - 1].AddStyleRun(LastRun); + } + } + + /// + /// Shaping (calculating widths, heights etc.) + /// + /// + /// Set to false for slower more exact positioning (very rarely neccesary) + void Shaping(bool shapeLight = true) + { + if (InputFragments != null && InputFragments.Count > 0) + { + foreach (var styleRun in StyleRuns) + { + var inputFrag = InputFragments[styleRun.FragmentIndex]; + var shaper = _engine.GetTextShaper(inputFrag.RichTextOptions.Family, inputFrag.RichTextOptions.SubFamily); + + if (shapeLight) + { + var shapedGlyphs = shaper.ShapeLight(styleRun.Text); + + double[] charWidths = new double[styleRun.Length + 1]; + shapedGlyphs.FillCharWidths((float)inputFrag.RichTextOptions.Size, charWidths, styleRun.Length + 1); + var spaceWidth = shaper.Shape(" ").GetWidthInPoints((float)inputFrag.RichTextOptions.Size); + + inputFrag.AscentPoints = shaper.GetAscentInPoints(inputFrag.RichTextOptions.Size); + inputFrag.DescentPoints = shaper.GetDescentInPoints(inputFrag.RichTextOptions.Size); + + int charIdx = styleRun.FullTextStart; + foreach (var width in charWidths) + { + if (charIdx < AllChars.Count) + { + AllChars[charIdx].Width = width; + charIdx++; + } + } + + styleRun.SetCharWidths(charWidths, spaceWidth); + } + else + { + throw new NotImplementedException("Proper shaping has not been implemented here yet"); + } + } + + var lastFragment = InputFragments[InputFragments.Count - 1]; + var lastRun = StyleRuns[StyleRuns.Count - 1]; + var lastShaper = _engine.GetTextShaper(lastFragment.RichTextOptions.Family, lastFragment.RichTextOptions.SubFamily); + var lastShapedGlyphs = lastShaper.ShapeLight(lastRun.Text); + double[] lastCharWidths = new double[lastRun.Length + 1]; + lastShapedGlyphs.FillCharWidths((float)lastFragment.RichTextOptions.Size, lastCharWidths, lastRun.Length + 1); + var LastspaceWidth = lastShaper.Shape(" ").GetWidthInPoints((float)lastFragment.RichTextOptions.Size); + + lastRun.SetCharWidths(lastCharWidths, LastspaceWidth); + } + } + + /// + /// Wrapping/line breaking + /// + /// + /// + /// + public TextLineCollection Wrap(double maxWidth) + { + if (InputFragments == null || InputFragments.Count <= 0) + { + return new TextLineCollection(); + } + var inputRt = InputFragments[0]; + var shaper = _engine.GetTextShaper(inputRt.RichTextOptions.Family, inputRt.RichTextOptions.SubFamily); + var layoutEngine = new TextLayoutEngine(_engine, shaper); + var wrappedLines = layoutEngine.WrapRichTextRuns(StyleRuns, maxWidth); + + if(wrappedLines.Count > 1) + { + //This could be done during wrapping technically for optimization + for (int i = 1; i < wrappedLines.Count; i++) + { + var startIdx = wrappedLines[i].InternalLineFragments[0].StartOriginal; + var len = wrappedLines[i].Text.Length; + for(int j = startIdx; j< (startIdx + len); j++) + { + AllChars[j].Line = i; + } + } + } + + WrappedLineCollection = new TextLineCollection(wrappedLines, InputFragments, true); + return WrappedLineCollection; + } + + /// + /// This returns the first letter with input 0,0 + /// The first two with 0,1 etc. + /// + /// + /// + /// + /// + private string GetSection(int startIdx, int endIdx) + { + if(startIdx > FullTextLastIdx) + { + throw new InvalidOperationException($"Cannot GetSection. StartIdx: '{startIdx}' is larger than LastIdx: '{FullTextLastIdx}' "); + } + if(endIdx > FullTextLastIdx) + { + throw new InvalidOperationException($"Cannot GetSection. EndIdx: '{endIdx}' is larger than LastIdx: '{FullTextLastIdx}'"); + } + var len = endIdx - startIdx + 1; + len = len + startIdx > (FullText.Length-1) ? FullTextLength - startIdx : len; + var subString = FullText.Substring(startIdx, len); + return subString; + } + + string GetFullText() + { + return FullText; + } + + public List GetTextOfAllTextRuns() + { + List runs = new List(); + foreach (var run in StyleRuns) + { + runs.Add(run.Text); + } + return runs; + } + + public int GetParagraphSeparatorCount() + { + return ParagraphSeparatorIndicies.Count; + } + + List GetCharInfoOfStyleRun(StyleRun run) + { + List infoLst = new List(); + for (int i = 0; i < run.Length; i++) + { + var charIdx = run.FullTextStart + i; + infoLst.Add(AllChars[charIdx]); + } + return infoLst; + } + + //Get paragraphindex + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/RichText/Paragraph.cs b/src/EPPlus.Fonts.OpenType/Integration/RichText/Paragraph.cs new file mode 100644 index 0000000000..a2697c2a6a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/RichText/Paragraph.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration.RichText +{ + internal class Paragraph : TextSection + { + private List _styleRuns = new List(); + internal Paragraph(int startIdx, int endIndex, Func getFullText, Func getText) : base(startIdx, endIndex, getFullText, getText) + { + } + + internal void AddStyleRun(StyleRun styleRun) + { + _styleRuns.Add(styleRun); + } + + //Return array so original list cannot be changed + internal StyleRun[] GetStyleRuns() + { + return _styleRuns.ToArray(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/RichText/StyleRun.cs b/src/EPPlus.Fonts.OpenType/Integration/RichText/StyleRun.cs new file mode 100644 index 0000000000..1d94a0c1ae --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/RichText/StyleRun.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration.RichText +{ + public class StyleRun : TextSection + { + internal int FragmentIndex { get; private set; } + internal double SpaceWidth { get; private set; } + + internal StyleRun(int fragmentIndex, int startIdx, int endIndex, Func getFullText, Func getText) : base(startIdx, endIndex, getFullText, getText) + { + FragmentIndex = fragmentIndex; + } + + private double[] _charWidths; + + internal void SetCharWidths(double[] charWidths, double spaceWidth) + { + _charWidths = charWidths; + SpaceWidth = spaceWidth; + } + + internal double GetCharWidthByIndex(int index) + { + return _charWidths[index]; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/RichText/TextSection.cs b/src/EPPlus.Fonts.OpenType/Integration/RichText/TextSection.cs new file mode 100644 index 0000000000..181806109d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/RichText/TextSection.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace EPPlus.Fonts.OpenType.Integration.RichText +{ + public class TextSection + { + int _startIdx; + int _endIdx; + + internal string FullText { get { return _getFullText(); } } + internal string Text { get { return _getText(_startIdx, _endIdx); } } + + Func _getFullText; + Func _getText; + + /// + /// Run starting char index in fulltext + /// + internal int FullTextStart { get { return _startIdx; } } + internal int Length + { get + { + return Text.Length; + } + } + + /// + /// A section of text between start and end index + /// + /// A function that gets the fulltext + /// + /// A function that takes the substring between + /// start and end index on the fulltext + internal TextSection(int startIdx, int endIndex, Func getFullText, Func getText) + { + _startIdx = startIdx; + _endIdx = endIndex; + _getFullText = getFullText; + _getText = getText; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextFragment.cs b/src/EPPlus.Fonts.OpenType/Integration/TextFragment.cs new file mode 100644 index 0000000000..54123d0f4c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextFragment.cs @@ -0,0 +1,75 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System.Drawing; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// Represents a text fragment with specific font properties. + /// + public class TextFragment : TextFragmentBase, ITextFragmentBase + { + /// + /// Legacy. This is to be replaced after PDF refactor is taken in + /// + public IFontFormatBase Font { get { return RichTextOptions; } set {RichTextOptions.SetFont(value); } } + + public TextFragment(IRichTextFormatSimple rtFormat) : base(rtFormat) + { + RichTextOptions = rtFormat; + } + public TextFragment():base() + { + RichTextOptions = new RichTextFormatSimple(); + } + + public new IRichTextFormatSimple RichTextOptions { get { return (IRichTextFormatSimple)base.RichTextOptions; } set { base.RichTextOptions = value; } } + + public override float Size { get => RichTextOptions.Size; } + } + + public class TextFragmentBase : ITextFragmentBase + { + public string Text { get => RichTextOptions.Text; set => RichTextOptions.Text = value; } + /// + /// Store rich-text info. + /// We must extract font info from this but nothing else is supposed to be done with this within opentype + /// but we hold the data so users may more easily recognize which rich text this is in the output. + /// + public virtual IRichTextFormatEssential RichTextOptions { get; set; } = new RichTextFormatBase(); + public ShapingOptions Options { get; set; } + public double AscentPoints { get; set; } + public double DescentPoints { get; set; } + + public string FullFontName + { + get + { + return $"{RichTextOptions.Family} {RichTextOptions.SubFamily.ToString().Replace(", ", " ")}"; + } + } + + public TextFragmentBase() + { + } + public TextFragmentBase(IRichTextFormatEssential richText) + { + RichTextOptions = richText; + } + public virtual float Size { get => RichTextOptions.Size; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextHandler.cs b/src/EPPlus.Fonts.OpenType/Integration/TextHandler.cs new file mode 100644 index 0000000000..2a5e44f0ea --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextHandler.cs @@ -0,0 +1,101 @@ +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Integration +{ + public class TextHandler + { + internal float CurrentFontSize { get; private set; } + + TextShaper _currentShaper; + TextLayoutEngine _currentLayout; + OpenTypeFontEngine _fontEngine; + + public TextHandler(OpenTypeFontEngine fontEngine, MeasurementFont mf) + { + CurrentFontSize = mf.Size; + _fontEngine = fontEngine; + SetFont(mf); + } + + public void SetFontSize(float fontSize) + { + CurrentFontSize = fontSize; + } + + public void SetFont(MeasurementFont mf) + { + CurrentFontSize = mf.Size; + _currentShaper = (TextShaper)_fontEngine.GetShaperForFont(mf); + _currentLayout = _fontEngine.GetTextLayoutEngineForFont(mf); + } + + /// + /// Gets single line spacing (baseline-to-baseline distance). + /// + public float GetLineHeightInPoints() + { + return _currentShaper.GetLineHeightInPoints(CurrentFontSize); + } + + /// + /// Calculates the total height of the font, in points. + /// + public float GetFontHeightInPoints() + { + return _currentShaper.GetFontHeightInPoints(CurrentFontSize); + } + + /// + /// Calculates the distance from the top of the font's bounding box to the baseline. + /// + /// The font size, in points, for which to calculate the baseline position. Must be a positive value. + /// The distance, in points, from the top of the font's bounding box to the baseline for the given font size. + public float GetAscentInPoints() + { + return _currentShaper.GetAscentInPoints(CurrentFontSize); + } + + /// + /// Calculates the font descent in points. + /// + public float GetDescentInPoints() + { + return _currentShaper.GetDescentInPoints(CurrentFontSize); + } + + /// + /// Measures the width of text in PDF points. + /// + public float MeasureTextInPoints(string text, ShapingOptions options = null) + { + return _currentShaper.MeasureTextInPoints(text, CurrentFontSize, options); + } + + /// + /// Measures the width of text in pixels. + /// + public float MeasureTextInPixels(string text, float dpi=96, ShapingOptions options = null) + { + return _currentShaper.MeasureTextInPixels(text, CurrentFontSize, dpi, options); + } + + /// + /// Measure multi-line text and return bounding box. + /// + public MultiLineMetrics MeasureLines(string text, ShapingOptions options) + { + return _currentShaper.MeasureLines(text, CurrentFontSize, options); + } + + public List WrapText( + string text, + double maxWidthPoints, + ShapingOptions options = null) + { + return _currentLayout.WrapText(text, CurrentFontSize, maxWidthPoints, 0, options); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Helpers.cs b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Helpers.cs new file mode 100644 index 0000000000..85186798fa --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Helpers.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using EPPlus.Fonts.OpenType.Utilities; +using OfficeOpenXml.Interfaces.Fonts; + + +namespace EPPlus.Fonts.OpenType.Integration +{ + public partial class TextLayoutEngine + { + private List CreateEmptyResult() + { + _lineListBuffer.Clear(); + _lineListBuffer.Add(string.Empty); + return new List(_lineListBuffer); + } + + private void PrepareLineBuilder(int textLength) + { + _lineBuilder.Clear(); + _lineBuilder.EnsureCapacity(textLength / 4 + 20); + } + + private double[] CalculateCharacterWidths(string text, float fontSize, ShapingOptions options) + { + var shaped = _shaper.ShapeLight(text, options); + var charWidths = GetCharWidthBuffer(text.Length); + Array.Clear(charWidths, 0, text.Length); + shaped.FillCharWidths(fontSize, charWidths, text.Length); + return charWidths; + } + + + + private CharacterType GetCharacterType(string text, int position) + { + if (position >= text.Length) + return CharacterType.EndOfText; + + if (text[position] == ' ') + return CharacterType.Space; + + return CharacterType.Regular; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.RichText.cs b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.RichText.cs new file mode 100644 index 0000000000..944e558124 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.RichText.cs @@ -0,0 +1,489 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + 01/22/2025 EPPlus Software AB Optimized with shaping cache + 01/23/2025 EPPlus Software AB Fixed lastSpaceIndex bug in multi-fragment wrapping + 02/23/2026 EPPlus Software AB Performance fix: Shape() → ShapeLight() in ProcessFragment + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Integration.RichText; +using EPPlus.Fonts.OpenType.Utilities; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// Rich text wrapping functionality for TextLayoutEngine. + /// + public partial class TextLayoutEngine + { + //public List WrapRichText( + // List fragments, + // double maxWidthPoints) + //{ + // var frags = fragments.Cast().ToList(); + // return WrapRichText(frags, maxWidthPoints); + //} + + /// + /// Wraps rich text with multiple fonts without full text concatenation. + /// Processes fragments sequentially with persistent line state. + /// + public List WrapRichText( + IEnumerable fragments, + double maxWidthPoints) + { + //Potentially optimize this '.Count()' method is slow + //Prefer the list parameter .Count but we also seemingly can't use List as input param + if (fragments == null || fragments.Count() == 0) + { + return new List { string.Empty }; + } + + _lineListBuffer.Clear(); + + var lineBuilder = new StringBuilder(512); + var state = new WrapStateRichText(0); + state.WordStart = -1; + state.LineStart = -1; + + foreach (var fragment in fragments) + { + if (string.IsNullOrEmpty(fragment.Text)) continue; + + ProcessFragment(fragment, maxWidthPoints, lineBuilder, state); + } + + FinalizeCurrentLine(lineBuilder, state.CurrentLineWidth, state.WordStart, state.CurrentTextLine); + state.EndCurrentTextLine(); + + + if (_lineListBuffer.Count == 0) + { + _lineListBuffer.Add(string.Empty); + } + + return new List(_lineListBuffer); + } + public List WrapRichText( + List textFragments, List fonts, + double maxWidthPoints) + { + TextFragmentCollectionSimple fragmentCollection = new TextFragmentCollectionSimple(fonts, textFragments); + return WrapRichText(fragmentCollection, maxWidthPoints); + } + + + public List WrapRichTextLines( + string text, MeasurementFont font, + double maxWidthPoints) + { + var tCollection = new TextFragmentCollectionSimple(new List() { font }, new List { text }); + return WrapRichTextLines(tCollection, maxWidthPoints); + } + + public TextLineCollection WrapRichTextLineCollection( + List fragments, + double maxWidthPoints) + { + var innerLines = WrapRichTextLines(fragments, maxWidthPoints); + var collection = new TextLineCollection(innerLines, fragments); + return collection; + } + + public TextLineCollection WrapRichTextLineCollection(List fragments, double maxWidthPoints) + { + var frags = fragments.Cast().ToList(); + return WrapRichTextLineCollection(frags, maxWidthPoints); + } + + public List WrapRichTextLines(List fragments, double maxWidthPoints) + { + var frags = fragments.Cast().ToList(); + return WrapRichTextLines(frags, maxWidthPoints); + } + + public List WrapRichTextLines( + List fragments, + double maxWidthPoints) + { + if (fragments == null || fragments.Count == 0) + { + return new List(); + } + + _lineListBuffer.Clear(); + + var lineBuilder = new StringBuilder(512); + var state = new WrapStateRichText(0); + state.WordStart = -1; + state.LineStart = -1; + + foreach (var fragment in fragments) + { + if (string.IsNullOrEmpty(fragment.Text)) continue; + + ProcessFragment(fragment, maxWidthPoints, lineBuilder, state); + } + + FinalizeCurrentLine(lineBuilder, state.CurrentLineWidth, state.WordStart, state.CurrentTextLine); + state.CurrentTextLine.Width = state.CurrentLineWidth; + state.CurrentTextLine.Text = lineBuilder.ToString(); + state.EndCurrentTextLine(); + + //Calculate ascent and descent so later application can handle line-spacing + //This could be optimized by doing it during ProcessFragment but that is way bulkier/unclear + foreach (var line in state.Lines) + { + double largestAscent = 0; + double largestDescent = 0; + double largestFontSize = 0; + foreach (var lineFragment in line.InternalLineFragments) + { + var frag = fragments[lineFragment.FragmentIndex]; + if (frag == null) continue; + largestAscent = Math.Max(frag.AscentPoints, largestAscent); + largestDescent = Math.Max(frag.DescentPoints, largestDescent); + largestFontSize = Math.Max(largestFontSize, frag.Size); + } + line.LargestAscent = largestAscent; + line.LargestDescent = largestDescent; + line.LargestFontSize = largestFontSize; + + line.FinalizeLineFragments(fragments); + } + + if (_lineListBuffer.Count == 0) + { + _lineListBuffer.Add(string.Empty); + } + + return state.Lines; + } + + public List WrapRichTextRuns( + List fragments, + double maxWidthPoints) + { + if (fragments == null || fragments.Count == 0) + { + return new List(); + } + + _lineListBuffer.Clear(); + + var lineBuilder = new StringBuilder(512); + var state = new WrapStateRichText(0); + state.WordStart = -1; + state.LineStart = -1; + + foreach (var fragment in fragments) + { + if (string.IsNullOrEmpty(fragment.Text)) continue; + + ProcessStyleRun(fragment, maxWidthPoints, lineBuilder, state); + } + + FinalizeCurrentLine(lineBuilder, state.CurrentLineWidth, state.WordStart, state.CurrentTextLine); + state.CurrentTextLine.Width = state.CurrentLineWidth; + state.CurrentTextLine.Text = lineBuilder.ToString(); + state.EndCurrentTextLine(); + + if (_lineListBuffer.Count == 0) + { + _lineListBuffer.Add(string.Empty); + } + + return state.Lines; + } + private void ProcessStyleRun( + StyleRun run, + double maxWidthPoints, + StringBuilder lineBuilder, + WrapStateRichText state) + { + state.CharIdxRt = 0; + state.CharIdxWithinOriginal = run.FullTextStart; + + int i = 0; + var len = run.Length; + while (i < (len)) + { + char c = run.Text[i]; + + if (IsLineBreak(c)) + { + HandleLineBreak(lineBuilder, state); + SkipLineBreakChars(run.Text, ref i); + + state.CurrentLineWidth = 0; + state.CurrentWordWidth = 0; + state.WordStart = -1; + state.LineStart = -1; + continue; + } + + //Must be done here rather than above the while loop since when a linebreak is the first char of a new linefragment it will produce empty internalLineFragments otherwise + if(i == 0) + { + state.LineFrag = new LineFragment(state.CurrentFragmentIdx, lineBuilder.Length, state.CharIdxRt, state.CharIdxWithinOriginal); + state.LineFrag.SpaceWidth = run.SpaceWidth; + } + + state.CharIdxRt = i; + + var cWidth = run.GetCharWidthByIndex(i); + + state.CurrentLineWidth += cWidth; + state.CurrentWordWidth += cWidth; + state.LineFrag.Width += cWidth; + + lineBuilder.Append(c); + + if (c == ' ') + { + state.SetAndLogWordStartState(lineBuilder.Length - 1); + } + + if (state.CurrentLineWidth > maxWidthPoints) + { + WrapCurrentLine(lineBuilder, state, maxWidthPoints, cWidth); + } + i++; + state.CharIdxWithinOriginal++; + state.CharIdxRt = i; + } + + if (state.LineFrag.Width > 0) + { + state.CurrentTextLine.InternalLineFragments.Add(state.LineFrag); + } + + state.CurrentFragmentIdx++; + } + + private void ProcessFragment( + ITextFragmentBase fragment, + double maxWidthPoints, + StringBuilder lineBuilder, + WrapStateRichText state) + { + state.CharIdxRt = 0; + var shaper = GetShaperForFont((IFontFormatBase)fragment.RichTextOptions); + var options = fragment.Options ?? ShapingOptions.Default; + int len = fragment.Text.Length; + var charWidths = GetCharWidthBuffer(len); + Array.Clear(charWidths, 0, len); + + // ShapeLight applies only kerning (sufficient for line-breaking). + // Full Shape() runs SingleAdjustment + Kerning + MarkToBase which + // is ~250x slower and irrelevant for wrapping decisions. + var shaped = shaper.ShapeLight(fragment.Text, options); + shaped.FillCharWidths(fragment.Size, charWidths, len); + + //Store for after everything is done + fragment.AscentPoints = shaper.GetAscentInPoints(fragment.Size); + fragment.DescentPoints = shaper.GetDescentInPoints(fragment.Size); + + var spaceWidth = shaper.Shape(" ", options).GetWidthInPoints(fragment.Size); + state.LineFrag = new LineFragment(state.CurrentFragmentIdx, lineBuilder.Length, state.CharIdxRt, state.CharIdxWithinOriginal); + state.LineFrag.SpaceWidth = spaceWidth; + + int i = 0; + while (i < len) + { + char c = fragment.Text[i]; + + if (IsLineBreak(c)) + { + HandleLineBreak(lineBuilder, state); + SkipLineBreakChars(fragment.Text, ref i); + + state.CurrentLineWidth = 0; + state.CurrentWordWidth = 0; + state.WordStart = -1; + state.LineStart = -1; + continue; + } + + state.CharIdxRt = i; + + state.CurrentLineWidth += charWidths[i]; + state.CurrentWordWidth += charWidths[i]; + state.LineFrag.Width += charWidths[i]; + + lineBuilder.Append(c); + + if (c == ' ') + { + state.SetAndLogWordStartState(lineBuilder.Length - 1); + } + + if (state.CurrentLineWidth > maxWidthPoints) + { + WrapCurrentLine(lineBuilder, state, maxWidthPoints, charWidths[i]); + } + i++; + state.CharIdxWithinOriginal++; + } + + if (state.LineFrag.Width > 0) + { + state.CurrentTextLine.InternalLineFragments.Add(state.LineFrag); + } + + state.CurrentFragmentIdx++; + } + + /// + /// Fills character widths from lightweight GlyphWidth structs (8 bytes each). + /// Used by the wrapping pipeline for optimal performance. + /// + private void FillCharWidths(GlyphWidth[] glyphs, double scale, int textLength, double[] charWidths) + { + for (int i = 0; i < glyphs.Length; i++) + { + int idx = glyphs[i].ClusterIndex; + if (idx >= 0 && idx < textLength) + { + charWidths[idx] += glyphs[i].XAdvance * scale; + } + } + } + + private bool IsLineBreak(char c) + { + return c == '\r' || c == '\n'; + } + + private void HandleLineBreak(StringBuilder lineBuilder, WrapStateRichText state) + { + if (lineBuilder.Length > 0 && lineBuilder[lineBuilder.Length - 1] == ' ') + { + lineBuilder.Length--; + } + if (lineBuilder.Length > 0) + { + _lineListBuffer.Add(lineBuilder.ToString()); + state.CurrentTextLine.Text = lineBuilder.ToString(); + } + else if (state.CurrentLineWidth > 0) + { + _lineListBuffer.Add(string.Empty); + state.CurrentTextLine.Text = string.Empty; + } + + state.CurrentTextLine.Width = state.CurrentLineWidth; + state.EndCurrentTextLineAndIntializeNext(0); + + lineBuilder.Length = 0; + } + + private void SkipLineBreakChars(string text, ref int i) + { + if (i < text.Length - 1 && text[i] == '\r' && text[i + 1] == '\n') + { + i++; + } + i++; + } + private void WrapCurrentLine(StringBuilder lineBuilder, WrapStateRichText state, double maxWidthPoints, double advanceWidth) + { + int fragIdxAtBreak = state.CurrentFragmentIdx; + + int adjustmentForLineBuilderLength = 0; + + // Bounds check to prevent ArgumentOutOfRangeException + if (state.WordStart >= 0 && state.WordStart < lineBuilder.Length) + { + var lineStringWithTrail = lineBuilder.ToString(0, state.WordStart + 1);//+1 was just added and should be here but everything else is sorta based on it being gone... + if (lineStringWithTrail[lineStringWithTrail.Length - 1] == ' ') + { + state.CurrentTextLine.WasWrappedOnSpace = true; + } + string line = lineStringWithTrail.TrimEnd(); + _lineListBuffer.Add(line); + lineBuilder.Remove(0, state.WordStart + 1); + + //handle line data + state.CurrentTextLine.Width = state.CurrentLineWidth - state.CurrentWordWidth; + state.CurrentTextLine.Text = line; + + fragIdxAtBreak = state.GetFragIdxAtWordStart(); + //Because of word-wrap we may have richTextFragments on the current line that is no longer part of it after wrap. + state.AdjustLineFragmentsForNextLine(); + + state.CurrentLineWidth = state.CurrentWordWidth; + state.LineStart = state.WordStart; + } + else + { + var lastChar = lineBuilder[lineBuilder.Length - 1]; + var line = lineBuilder.ToString(0, lineBuilder.Length - 1); + // No valid space found - wrap entire line + _lineListBuffer.Add(line); + + //handle line data + state.CurrentTextLine.Width = state.CurrentLineWidth - advanceWidth; + state.CurrentTextLine.Text = line; + //state.CurrentTextLine. + + //Add the char that went over max to the next line + state.CurrentLineWidth = 0; + lineBuilder.Length = 0; + + //Append the char that goes over max unless it is a space + if (lastChar != ' ') + { + lineBuilder.Append(lastChar); + //Since we appended we should remove it from line builder length when end current and initialize next happens + adjustmentForLineBuilderLength = 1; + + //The char that made us move past maxWidth + //must be added to the new line + state.CurrentWordWidth = advanceWidth; + state.CurrentLineWidth = advanceWidth; + } + else + { + state.CurrentTextLine.WasWrappedOnSpace = true; + } + } + + state.EndCurrentTextLineAndIntializeNext(lineBuilder.Length - adjustmentForLineBuilderLength); + state.CurrentWordWidth = state.CurrentLineWidth; + + state.WordStart = -1; + state.LineStart = -1; + } + + private void FinalizeCurrentLine(StringBuilder lineBuilder, double lineWidth, int lastSpaceIndex, TextLineSimple currentLine) + { + if (lineBuilder.Length > 0) + { + if (lineBuilder[lineBuilder.Length - 1] == ' ') + { + currentLine.WasWrappedOnSpace = true; + lineBuilder.Length--; + } + if (lineBuilder.Length > 0) + { + _lineListBuffer.Add(lineBuilder.ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Wrapping.cs b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Wrapping.cs new file mode 100644 index 0000000000..1fc1abb9ca --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.Wrapping.cs @@ -0,0 +1,197 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + 01/22/2025 EPPlus Software AB Optimized with shaping cache + 01/23/2025 EPPlus Software AB Fixed lastSpaceIndex bug in multi-fragment wrapping + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + public partial class TextLayoutEngine + { + /// + /// Processes a complete word (reached space or end of text). + /// Decides whether to add it to current line or start a new line. + /// + private void ProcessCompleteWord( + string text, + WrapStateText state, + int currentPos, + double maxWidth) + { + double totalWidth = state.CurrentLineWidth + state.CurrentWordWidth; + + if (currentPos != text.Length && text[currentPos] == ' ') + { + totalWidth += state.SpaceWidth; + } + + if (totalWidth <= maxWidth || state.LineStart == state.WordStart) + { + // Word fits on current line + if(_lineBuilder.LastChar() != ' ') + { + _lineBuilder.AppendSpaceIfNotEmpty(); + } + _lineBuilder.AppendSubstring(text, state.WordStart, currentPos - state.WordStart); + state.CurrentLineWidth = totalWidth; + } + else + { + + if(totalWidth - state.SpaceWidth <= maxWidth) + { + // Word doesn't fit - but does fit without space width + //we discard the space + _lineBuilder.AppendSpaceIfNotEmpty(); + _lineBuilder.AppendSubstring(text, state.WordStart, currentPos - state.WordStart); + state.CurrentLineWidth = totalWidth; + } + else + { + // Word doesn't fit - start new line + _lineBuilder.FlushToList(_lineListBuffer); + _lineListBuffer[_lineListBuffer.Count - 1] += " "; + + state.LineStart = state.WordStart; + state.CurrentLineWidth = state.CurrentWordWidth; + + _lineBuilder.AppendSubstring(text, state.WordStart, currentPos - state.WordStart); + } + } + + state.WordStart = currentPos + 1; + state.CurrentWordWidth = 0; + } + + private void ProcessNonEndingSpace(string text, + WrapStateText state, + int currentPos, + double maxWidth + ) + { + var totalWidth = state.CurrentLineWidth + state.SpaceWidth; + + if (totalWidth <= maxWidth) + { + _lineBuilder.Append(" "); + _lineBuilder.AppendSubstring(text, state.WordStart, currentPos - state.WordStart); + state.CurrentLineWidth = totalWidth; + } + else + { + // Word doesn't fit - start new line + _lineBuilder.FlushToList(_lineListBuffer); + + state.LineStart = state.WordStart; + state.CurrentLineWidth = state.CurrentWordWidth; + + _lineBuilder.AppendSubstring(text, state.WordStart, currentPos - state.WordStart); + } + + state.WordStart = currentPos + 1; + //Word width likely always 0 here before and after + //state.CurrentWordWidth = 0; + } + + private void ProcessCharacterInWord( + string text, + double[] charWidths, + WrapStateText state, + int currentPos, + double maxWidth) + { + state.CurrentWordWidth += charWidths[currentPos]; + + // CASE 1: Line has content and word grows too large + if ((state.CurrentWordWidth + state.CurrentLineWidth) > maxWidth && + state.LineStart < state.WordStart && + state.CurrentLineWidth > 0) + { + _lineBuilder.FlushToList(_lineListBuffer); + state.LineStart = state.WordStart; + state.CurrentLineWidth = 0; + } + + // CASE 2: Word is alone on line and too long - break it + if (state.LineStart == state.WordStart && state.CurrentWordWidth > maxWidth) + { + BreakLongWord(text, charWidths, state, currentPos, maxWidth); + } + } + + /// + /// Breaks a word that is too long to fit on a single line. + /// Uses backward removal strategy: removes characters from the end until the word fits. + /// + private void BreakLongWord( + string text, + double[] charWidths, + WrapStateText state, + int currentPos, + double maxWidth) + { + int breakPoint = currentPos + 1; + double currentWidth = state.CurrentWordWidth; + + // Remove characters from the end until it fits + while (breakPoint > state.WordStart + 1 && currentWidth > maxWidth) + { + breakPoint--; + currentWidth -= charWidths[breakPoint]; + } + + // Safety: at least 1 character must fit + if (breakPoint <= state.WordStart) + { + breakPoint = state.WordStart + 1; + } + + // Add what fits on current line + _lineBuilder.AppendSubstring(text, state.WordStart, breakPoint - state.WordStart); + _lineListBuffer.Add(_lineBuilder.ToString()); + _lineBuilder.Clear(); + + // Calculate width of remaining part + state.CurrentWordWidth = 0; + for (int j = breakPoint; j <= currentPos; j++) + { + if (j < text.Length) + { + state.CurrentWordWidth += charWidths[j]; + } + } + + // Update state + state.WordStart = breakPoint; + state.LineStart = breakPoint; + state.CurrentLineWidth = 0; + } + + private List FinalizeWrapping() + { + _lineBuilder.FlushToList(_lineListBuffer); + + if (_lineListBuffer.Count == 0) + { + _lineListBuffer.Add(string.Empty); + } + + return new List(_lineListBuffer); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.cs b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.cs new file mode 100644 index 0000000000..5b0d08037d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.cs @@ -0,0 +1,296 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + 01/22/2025 EPPlus Software AB Optimized with shaping cache + 01/23/2025 EPPlus Software AB Added ArrayPool optimization + 01/23/2025 EPPlus Software AB Added space width cache + 01/24/2025 EPPlus Software AB Added StringBuilder pooling (.NET 3.5 compatible) + 05/06/2026 EPPlus Software AB Removed per-instance font directories — uses global config + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utilities; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + /// + /// Handles text wrapping and layout using proper OpenType shaping. + /// Replaces the old TextData wrapping logic. + /// + public partial class TextLayoutEngine : IDisposable + { + private readonly ITextShaper _shaper; + private readonly OpenTypeFontEngine _engine; + + // Space width cache - avoids repeated Shape(" ") calls + private readonly Dictionary _spaceWidthCache; + + // ArrayPool buffer - only ONE buffer for entire class + private double[] _charWidthBuffer = null; + private int _charWidthBufferCapacity = 0; + + // StringBuilder pooling - reuse between wrapping operations + private readonly StringBuilder _lineBuilder = new StringBuilder(256); + + private List _lineListBuffer = new List(256); + private bool _disposed = false; + + /// + /// Creates a TextLayoutEngine for single-font text wrapping. + /// Font resolution for rich-text fragments uses the globally configured resolver — to + /// search additional directories or install a custom resolver, use + /// . + /// + public TextLayoutEngine(ITextShaper shaper) + { + _shaper = shaper ?? throw new ArgumentNullException(nameof(shaper)); + _spaceWidthCache = new Dictionary(); + } + + /// + /// Creates a TextLayoutEngine backed by a font engine, enabling per-fragment font resolution + /// for multi-font rich text. + /// + public TextLayoutEngine(OpenTypeFontEngine engine, ITextShaper shaper) + { + _engine = engine ?? throw new ArgumentNullException(nameof(engine)); + _shaper = shaper ?? throw new ArgumentNullException(nameof(shaper)); + _spaceWidthCache = new Dictionary(); + } + + public double GetLineHeightInPoints(float fontSize) + { + return _shaper.GetLineHeightInPoints(fontSize); + } + + public double GetBaseLineInPoints(float fontSize) + { + return _shaper.GetAscentInPoints(fontSize); + } + + public double GetDescentInPoints(float fontSize) + { + return _shaper.GetDescentInPoints(fontSize); + } + + /// + /// Gets a char width buffer with at least the specified capacity. + /// Reuses existing buffer if large enough, otherwise rents larger one from pool. + /// + private double[] GetCharWidthBuffer(int minimumLength) + { + return ArrayPoolHelper.EnsureCapacity( + ref _charWidthBuffer, + ref _charWidthBufferCapacity, + minimumLength, + clearArray: false + ); + } + + /// + /// Gets cached space width for the given font size. + /// Caches the result to avoid repeated Shape(" ") calls. + /// + private double GetCachedSpaceWidth(float fontSize, ShapingOptions options) + { + // Check cache first + if (_spaceWidthCache.TryGetValue(fontSize, out double cachedWidth)) + { + return cachedWidth; + } + + // Measure and cache + double width = MeasureText(" ", fontSize, options); + _spaceWidthCache[fontSize] = width; + + return width; + } + + public List WrapText( + string text, + float fontSize, + double maxWidthPoints, + ShapingOptions options = null) + { + return WrapText(text, fontSize, maxWidthPoints, 0, options); + } + + public List WrapText( + string text, + float fontSize, + double maxWidthPoints, + double preExistingWidthPoints, + ShapingOptions options = null) + { + if (string.IsNullOrEmpty(text)) + { + return new List { string.Empty }; + } + + options = options ?? ShapingOptions.Default; + var lines = new List(); + + var paragraphs = text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + //paragraphs that have endline symbols should keep trailing spaces + //others should not. Add an extra space as the trailing space is always trimmed + //if (paragraphs.Length > 1) + //{ + // for (int i = 1; i < paragraphs.Length - 1; i++) + // { + // paragraphs[i] = paragraphs[i] + " "; + // } + //} + + bool isFirstLine = true; + foreach (var paragraph in paragraphs) + { + if (string.IsNullOrEmpty(paragraph)) + { + lines.Add(string.Empty); + isFirstLine = false; + continue; + } + + double startingWidth = isFirstLine ? preExistingWidthPoints : 0; + var wrappedLines = WrapParagraph(paragraph, fontSize, maxWidthPoints, startingWidth, options); + lines.AddRange(wrappedLines); + + isFirstLine = false; + } + + return lines; + } + + private List WrapParagraph( + string text, + float fontSize, + double maxWidthPoints, + double startingWidthPoints, + ShapingOptions options) + { + _lineListBuffer.Clear(); + + if (string.IsNullOrEmpty(text)) + { + return CreateEmptyResult(); + } + + var charWidths = CalculateCharacterWidths(text, fontSize, options); + + var state = new WrapStateText(startingWidthPoints, GetCachedSpaceWidth(fontSize, options)); + + PrepareLineBuilder(text.Length); + + for (int i = 0; i <= text.Length; i++) + { + var charType = GetCharacterType(text, i); + + if (state.IsCompleteWordReady(charType, i)) // ← Använd state + { + ProcessCompleteWord(text, state, i, maxWidthPoints); + } + else if (charType == CharacterType.Space) + { + ProcessNonEndingSpace(text, state, i, maxWidthPoints); + } + else if (charType == CharacterType.Regular) + { + ProcessCharacterInWord(text, charWidths, state, i, maxWidthPoints); + } + else + { + if (text[i - 1] == ' ') + { //Add extra to avoid trimming + _lineBuilder.Append(" "); + //if (_lineBuilder.LastChar() == ' ') + //{ + // //Add extra to avoid trimming + // _lineBuilder.Append(" "); + //} + } + } + } + + return FinalizeWrapping(); + } + + + private double MeasureText(string text, float fontSize, ShapingOptions options) + { + if (string.IsNullOrEmpty(text)) + { + return 0; + } + + var shaped = _shaper.Shape(text, options); + return shaped.GetWidthInPoints(fontSize); + } + + private ITextShaper GetShaperForFont(IFontFormatBase font) + { + if (_engine != null) + { + return _engine.GetShaperForFont(font); + } + + // No engine available (single-font constructor): the only shaper we have is our own. + return _shaper; + } + + + #region IDisposable Implementation + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + // Return buffer to pool + if (_charWidthBuffer != null) + { + ArrayPoolHelper.SafeReturn(ref _charWidthBuffer, clearArray: false); + _charWidthBufferCapacity = 0; + } + + // Clear StringBuilder to release string references (.NET 3.5 compatible) + _lineBuilder.Length = 0; + + // Clear space width cache + _spaceWidthCache.Clear(); + } + + _disposed = true; + } + } + + ~TextLayoutEngine() + { + Dispose(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Integration/WrapStateBase.cs b/src/EPPlus.Fonts.OpenType/Integration/WrapStateBase.cs new file mode 100644 index 0000000000..97390c7834 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/WrapStateBase.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + internal abstract class WrapStateBase + { + public int LineStart { get; set; } + public int WordStart { get; set; } + public double CurrentLineWidth { get; set; } + public double CurrentWordWidth { get; set; } + + /// + /// Data holders for the individual lines + /// + public List Lines = new List(); + + public TextLineSimple CurrentTextLine = new TextLineSimple(); + + internal int CurrentFragmentIdx = 0; + + public bool IsCompleteWordReady(CharacterType charType, int currentPosition) + { + return (charType == CharacterType.Space || charType == CharacterType.EndOfText) + && WordStart < currentPosition; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/WrapStateRichText.cs b/src/EPPlus.Fonts.OpenType/Integration/WrapStateRichText.cs new file mode 100644 index 0000000000..819273f383 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/WrapStateRichText.cs @@ -0,0 +1,161 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Integration +{ + internal class WrapStateRichText : WrapStateBase + { + internal LineFragment LineFrag = null; + internal int CharIdxRt = 0; + internal int CharIdxWithinOriginal = 0; + + public WrapStateRichText(double lineWidth) + { + CurrentLineWidth = lineWidth; + } + + internal void EndCurrentTextLine() + { + if (CurrentTextLine.InternalLineFragments.Contains(LineFrag) == false) + { + CurrentTextLine.InternalLineFragments.Add(LineFrag); + } + Lines.Add(CurrentTextLine); + } + + internal void EndCurrentTextLineAndIntializeNext(int startIdxOfNewFragment) + { + var nextLine = new TextLineSimple(); + + if (_fragmentsForNextLine == null) + { + EndCurrentTextLine(); + var spcWidthTemp = LineFrag.SpaceWidth; + LineFrag = new LineFragment(CurrentFragmentIdx, startIdxOfNewFragment, CharIdxRt, CharIdxWithinOriginal); + LineFrag.SpaceWidth = spcWidthTemp; + } + else + { + //_fragmentsForNextLine.Add(LineFrag); + nextLine.InternalLineFragments = _fragmentsForNextLine; + + //LineFrag.StartIdx = ; + Lines.Add(CurrentTextLine); + _fragmentsForNextLine = null; + } + CurrentTextLine = nextLine; + } + + int _rtIdxAtWordStart = -1; + int _listIdxWithinLine = -1; + int _totalCharsAtWordStart = -1; + int _charIdxRtAtWordStart = -1; + double _lineFragWidthAtWordStart = -1; + + internal void SetAndLogWordStartState(int wordStart) + { + WordStart = wordStart; + CurrentWordWidth = 0; + + _rtIdxAtWordStart = CurrentFragmentIdx; + _lineFragWidthAtWordStart = LineFrag.Width; + + //Since we don't want the space itself to be the start pos but the first letter of the word. Use +1 + //TODO: Handle when no word after? Its never used if there isn't one so arguably we don't have to. + _totalCharsAtWordStart = CharIdxWithinOriginal + 1; + _charIdxRtAtWordStart = CharIdxRt + 1; + + if (CurrentTextLine.InternalLineFragments.Count == 0) + { + _listIdxWithinLine = 0; + return; + } + + _listIdxWithinLine = CurrentTextLine.InternalLineFragments.Count - 1; + + if (CurrentTextLine.InternalLineFragments[_listIdxWithinLine].FragmentIndex < _rtIdxAtWordStart) + { + //When the word begins we are on a fragment that has not yet been added to the list. + //It will be the next index when added + _listIdxWithinLine += 1; + } + } + + internal int GetFragIdxAtWordStart() + { + return _rtIdxAtWordStart; + } + + internal double GetFragmentWidthAtWordStart() + { + return _lineFragWidthAtWordStart; + } + + List _fragmentsForNextLine = null; + + internal void AdjustLineFragmentsForNextLine() + { + if(_rtIdxAtWordStart == CurrentFragmentIdx) + { + //If we are On the fragment we have not added it yet + //Do so before splitting + CurrentTextLine.InternalLineFragments.Add(LineFrag); + } + else + { + + } + + var origFragment = CurrentTextLine.InternalLineFragments[_listIdxWithinLine]; + + //var wordStartPos = _totalCharsAtWordStart; + //var wordBreakPos2 = CharIdxWithinOriginal; + //var endIndexOfOrigFragment = _charIdxRtAtWordStart; + //var startIdxNewFragment = endIndexOfOrigFragment - + //var lnFragNewStartIdx = CharIdxWithinOriginal - _totalCharsAtWordStart; + + var resultingFragment = CurrentTextLine.SplitAndGetLeftoverLineFragment(ref origFragment, _lineFragWidthAtWordStart, _charIdxRtAtWordStart, _totalCharsAtWordStart); + CurrentTextLine.InternalLineFragments[_listIdxWithinLine] = origFragment; + + _fragmentsForNextLine = new List(); + + //Iterate backwards from back of list until we hit fragment + for (int i = CurrentTextLine.InternalLineFragments.Count()-1; i > _listIdxWithinLine; i--) + { + //The current fragment's startidx is affected by the split if it is not the first in new line + if (CurrentTextLine.InternalLineFragments[i].StartIdx != 0) + { + CurrentTextLine.InternalLineFragments[i].StartIdx -= WordStart + 1; + } + //Add fragment to the new list + _fragmentsForNextLine.Insert(0, CurrentTextLine.InternalLineFragments[i]); + //Remove it from the old + CurrentTextLine.InternalLineFragments.RemoveAt(i); + } + + if (_rtIdxAtWordStart != CurrentFragmentIdx) + { + if (resultingFragment.Width != 0) + { + //We also insert the fragment we've split out + //Unless the leftover is an empty fragment (this happens when we wrap on a space that had to be trimmed) + _fragmentsForNextLine.Insert(0, resultingFragment); + } + //The current fragment's startidx is affected by the split if it is not the first in new line + if (LineFrag.StartIdx != 0) + { + LineFrag.StartIdx -= WordStart + 1; + } + } + else + { + LineFrag = resultingFragment; + } + + _rtIdxAtWordStart = -1; + _listIdxWithinLine = -1; + _lineFragWidthAtWordStart = -1; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Integration/WrapStateText.cs b/src/EPPlus.Fonts.OpenType/Integration/WrapStateText.cs new file mode 100644 index 0000000000..5bc90c0af3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Integration/WrapStateText.cs @@ -0,0 +1,27 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB TextLayoutEngine implementation + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Integration +{ + internal class WrapStateText : WrapStateBase + { + public WrapStateText(double lineWidth, double spaceWidth) + { + CurrentLineWidth = lineWidth; + SpaceWidth = spaceWidth; + } + + public double SpaceWidth { get; set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFont.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFont.cs new file mode 100644 index 0000000000..6fdb0e651c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFont.cs @@ -0,0 +1,803 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Hhea; +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using EPPlus.Fonts.OpenType.Tables.Kern; +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using EPPlus.Fonts.OpenType.Tables.Name; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.Tables.Post; +using EPPlus.Fonts.OpenType.Tables.Vhea; +using EPPlus.Fonts.OpenType.Tables.Vmtx; +using EPPlus.Fonts.OpenType.Utils; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Base class for open-type fonts + /// + [DebuggerDisplay("{FullName}, IsSubset: {IsSubset}")] + public class OpenTypeFont + { + internal TableCache _localTableCache; + internal TableLoaderCache _loaderCache; + internal TableLoaderSettings _tblSettings; + private readonly byte[] _fontBytes; + protected Dictionary _tableRecords; + public FontFormat Format; + private readonly object _syncRoot = new object(); + + + internal OpenTypeFont(FontFormat format, bool isSubset = false) + { + Format = format; + _tableRecords = new Dictionary(); + _localTableCache = new TableCache(); + _loaderCache = new TableLoaderCache(); + IsSubset = isSubset; + } + + + internal OpenTypeFont(byte[] fontBytes) + : this(fontBytes, -1) + { + } + + internal OpenTypeFont(byte[] fontBytes, long startOffset) + { + if (fontBytes == null || fontBytes.Length < 4) + throw new ArgumentException("Invalid font data: too short to contain a valid SFNT header.", nameof(fontBytes)); + + Format = DetectFormat(fontBytes, startOffset > -1 ? startOffset : 0); + + _fontBytes = fontBytes; + var tableReaderFactory = new FontTableReaderFactory(fontBytes); + using var reader = tableReaderFactory.CreateReader(startOffset); + + lock (_syncRoot) + { + if (startOffset > -1) + { + reader.BaseStream.Position = startOffset; + } + + Initialize(reader); // Reads SFNT header + ReadTableRecords(reader); // Reads table directory + } + + + _localTableCache = new TableCache(); + _loaderCache = new TableLoaderCache(); + _tblSettings = new TableLoaderSettings(tableReaderFactory, _tableRecords, _localTableCache, _loaderCache); + + //Ensure lazy-loading of individual tables via instanced table loaders. + _os2TableLoader = TableLoaders.GetOs2TableLoader(_tblSettings); + _nameTableLoader = TableLoaders.GetNameTableLoader(_tblSettings); + _hheaTableLoader = TableLoaders.GetHheaTableLoader(_tblSettings); + _headTableLoader = TableLoaders.GetHeadTableLoader(_tblSettings); + _cmapTableLoader = TableLoaders.GetCmapTableLoader(_tblSettings); + _hmtxTableLoader = TableLoaders.GetHmtxTableLoader(_tblSettings); + _maxpTableLoader = TableLoaders.GetMaxpTableLoader(_tblSettings); + _postTableLoader = TableLoaders.GetPostTableLoader(_tblSettings); + _locaTableLoader = TableLoaders.GetLocaTableLoader(_tblSettings); + + // ✅ Optional tables - only create loader if table exists + _gsubTableLoader = TableRecords.ContainsKey(TableNames.Gsub) + ? TableLoaders.GetGsubTableLoader(_tblSettings) + : null; + _gposTableLoader = TableRecords.ContainsKey(TableNames.Gpos) + ? TableLoaders.GetGposTableLoader(_tblSettings) + : null; + _glyfTableLoader = TableRecords.ContainsKey(TableNames.Glyf) + ? TableLoaders.GetGlyfTableLoader(_tblSettings) + : null; + _kernTableLoader = TableRecords.ContainsKey(TableNames.Kern) + ? TableLoaders.GetKernTableLoader(_tblSettings) + : null; + _vheaTableLoader = TableRecords.ContainsKey(TableNames.Vhea) + ? TableLoaders.GetVheaTableLoader(_tblSettings) + : null; + _vmtxTableLoader = TableRecords.ContainsKey(TableNames.Vmtx) + ? TableLoaders.GetVmtxTableLoader(_tblSettings) + : null; + } + + /// + /// Detects the font format from the SFNT version field in the header. + /// + /// Raw font bytes + /// Offset to the start of the SFNT header + /// Detected FontFormat + /// Thrown if the header contains an unrecognized SFNT version + private static FontFormat DetectFormat(byte[] fontBytes, long offset) + { + // sfntVersion is a big-endian UInt32 at the start of the SFNT header + uint sfntVersion = + ((uint)fontBytes[offset + 0] << 24) | + ((uint)fontBytes[offset + 1] << 16) | + ((uint)fontBytes[offset + 2] << 8) | + ((uint)fontBytes[offset + 3]); + + switch (sfntVersion) + { + case 0x00010000: // TrueType + case 0x74727565: // 'true' — Apple TrueType + return FontFormat.Ttf; + + case 0x4F54544F: // 'OTTO' — OpenType/CFF + case 0x74797031: // 'typ1' — PostScript Type 1 + return FontFormat.Otf; + + default: + throw new ArgumentException( + $"Unrecognized SFNT version 0x{sfntVersion:X8}. " + + "The data does not appear to be a valid TTF or OTF font.", + "fontBytes"); + } + } + + Os2TableLoader _os2TableLoader; + NameTableLoader _nameTableLoader; + HheaTableLoader _hheaTableLoader; + VheaTableLoader _vheaTableLoader; + HeadTableLoader _headTableLoader; + CmapTableLoader _cmapTableLoader; + HmtxTableLoader _hmtxTableLoader; + VmtxTableLoader _vmtxTableLoader; + MaxpTableLoader _maxpTableLoader; + PostTableLoader _postTableLoader; + LocaTableLoader _locaTableLoader; + GsubTableLoader _gsubTableLoader; + GposTableLoader _gposTableLoader; + + internal GlyfTableLoader _glyfTableLoader; + internal KernTableLoader _kernTableLoader; + private volatile bool _fullyLoaded = false; + + public bool FullyLoaded => _fullyLoaded; + internal bool IsReadOnly { get; set; } + + internal void EnsureFullyLoaded() + { + if (_fullyLoaded) + return; + + lock (_loaderCache.SyncLock) + { + + // --- Required tables (always present in valid fonts) --- + // Each property accessor calls its TableLoader.Load() which + // reads from the byte[] stream and caches the result. + // By accessing them all here under the font-level lock, + // we guarantee no concurrent reader access. + FontTableBase _ = CmapTable; + _ = HeadTable; + _ = HheaTable; + _ = HmtxTable; + _ = MaxpTable; + _ = NameTable; + _ = Os2Table; + _ = PostTable; + _ = LocaTable; + + // --- Optional tables (only if present in font) --- + if (_gsubTableLoader != null) + { + var gsub = GsubTable; // Forces full GSUB parse + } + if (_gposTableLoader != null) + { + var gpos = GposTable; // Forces full GPOS parse (incl. MarkToBase subtables) + } + if (_glyfTableLoader != null) + { + var glyf = GlyfTable; // Forces full glyph outline parse + } + if (_kernTableLoader != null) + { + var kern = KernTable; // Forces legacy kern table parse + } + + _fullyLoaded = true; + } + } + + internal FontSerializationContext GetSerializationContext() + { + return new FontSerializationContext(this); + } + + public FontValidationReport ValidateFont(FontValidationSeverity severity) + { + var validator = new FontValidator(); + return validator.Validate(this); + } + + + internal List UsedCodePointsForSubset { get; set; } = new List(); + + /// + /// Any font file that does not contain all of the below tables can be considered corrupt as "the following tables are required for the font to function correctly" + /// source: https://learn.microsoft.com/en-us/typography/opentype/spec/otff + /// + #region Required Font Tables + public CmapTable CmapTable + { + get + { + if (_cmapTableLoader != null) + { + return _cmapTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Cmap)) + { + return (CmapTable)_localTableCache.Get(TableNames.Cmap); + } + return null; + } + } + public HeadTable HeadTable + { + get + { + if (_headTableLoader != null) + { + return _headTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Head)) + { + return (HeadTable)_localTableCache.Get(TableNames.Head); + } + return null; + } + } + public HheaTable HheaTable + { + get + { + if (_hheaTableLoader != null) + { + return _hheaTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Hhea)) + { + return (HheaTable)_localTableCache.Get(TableNames.Hhea); + } + return null; + } + } + + public VheaTable VheaTable + { + get + { + if (_vheaTableLoader != null) + { + return _vheaTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Vhea)) + { + return (VheaTable)_localTableCache.Get(TableNames.Vhea); + } + return null; + } + } + + public HmtxTable HmtxTable + { + get + { + if (_hmtxTableLoader != null) + { + return _hmtxTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Hmtx)) + { + return (HmtxTable)_localTableCache.Get(TableNames.Hmtx); + } + return null; + } + + } + + public VmtxTable VmtxTable + { + get + { + if (_vmtxTableLoader != null) + { + return _vmtxTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Vmtx)) + { + return (VmtxTable)_localTableCache.Get(TableNames.Vmtx); + } + return null; + } + } + + public MaxpTable MaxpTable + { + get + { + if (_maxpTableLoader != null) + { + return _maxpTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Maxp)) + { + return (MaxpTable)_localTableCache.Get(TableNames.Maxp); + } + return null; + } + } + public NameTable NameTable + { + get + { + if (_nameTableLoader != null) + { + return _nameTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Name)) + { + return (NameTable)_localTableCache.Get(TableNames.Name); + } + return null; + } + } + public Os2Table Os2Table + { + get + { + if (_os2TableLoader != null) + { + return _os2TableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Os2)) + { + return (Os2Table)_localTableCache.Get(TableNames.Os2); + } + return null; + } + } + public PostTable PostTable + { + get + { + if (_postTableLoader != null) + { + return _postTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Post)) + { + return (PostTable)_localTableCache.Get(TableNames.Post); + } + return null; + } + } + + public LocaTable LocaTable + { + get + { + if (_locaTableLoader != null) + { + return _locaTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Loca)) + { + return (LocaTable)_localTableCache.Get(TableNames.Loca); + } + return null; + } + } + #endregion + + //Extra accessors for common tables + public GlyfTable GlyfTable + { + get + { + if (_glyfTableLoader != null) + { + return _glyfTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Glyf)) + { + return (GlyfTable)_localTableCache.Get(TableNames.Glyf); + } + else + { + return null; + } + } + } + public KernTable KernTable + { + get + { + if (_kernTableLoader != null) + { + return _kernTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Kern)) + { + return (KernTable)_localTableCache.Get(TableNames.Kern); + } + else + { + return null; + } + } + } + + public GsubTable GsubTable + { + get + { + if (_gsubTableLoader != null) + { + return _gsubTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Gsub)) + { + return (GsubTable)_localTableCache.Get(TableNames.Gsub); + } + else + { + return null; + } + } + } + + public GposTable GposTable + { + get + { + if (_gposTableLoader != null) + { + return _gposTableLoader.Load(); + } + else if (_localTableCache.Contains(TableNames.Gpos)) + { + return (GposTable)_localTableCache.Get(TableNames.Gpos); + } + else + { + return null; + } + } + } + + private void Initialize(FontsBinaryReader reader) + { + SfntVersion = reader.ReadUInt32BigEndian(); + // Number of tables. + NumTables = reader.ReadUInt16BigEndian(); + // Maximum power of 2 less than or equal to numTables, + // times 16 ((2**floor(log2(numTables))) * 16, + // where “**” is an exponentiation operator). + SearchRange = reader.ReadUInt16BigEndian(); + // Log2 of the maximum power of 2 less than or equal to + // numTables (log2(searchRange/16), which is equal to + // floor(log2(numTables))). + EntrySelector = reader.ReadUInt16BigEndian(); + // numTables times 16, minus searchRange + // ((numTables * 16) - searchRange). + RangeShift = reader.ReadUInt16BigEndian(); + } + + private void ReadTableRecords(FontsBinaryReader reader) + { + _tableRecords = new Dictionary(); + for (var x = 0; x < NumTables; x++) + { + var record = new TableRecord + { + Tag = new Tag(reader), + Checksum = reader.ReadUInt32BigEndian(), + Offset = reader.ReadUInt32BigEndian(), + Length = reader.ReadUInt32BigEndian() + }; + _tableRecords.Add(record.Tag.Value, record); + } + } + + public string FullName + { + get + { + var n = GetEnglishFullFontFamilyName(); + if (string.IsNullOrEmpty(n)) + { + return "Unknown font"; + } + return n; + } + } + + public string SubFamily + { + get + { + var n = GetEnglishFontSubFamilyName(); + if (string.IsNullOrEmpty(n)) + { + return "Unknown subfamily"; + } + return n; + } + } + + public bool IsSubset + { + get; private set; + } + + public string GetEnglishFullFontFamilyName() + { + return GetNameString(NameRecordTypes.FullFontName); + } + + public string GetEnglishFontFamilyName() + { + return GetNameString(NameRecordTypes.FontFamilyName); + } + + public string GetEnglishFontSubFamilyName() + { + return GetNameString(NameRecordTypes.FontSubfamilyName); + } + + private string GetNameString(NameRecordTypes recordType) + { + // Priority 1: Windows English (Platform 3, Language 0x0409) + var windowsEnglish = NameTable.NameRecords.FirstOrDefault(x => + x.platformId == 3 && + x.languageID == 0x0409 && + x.RecordType == recordType); + + if (windowsEnglish != null && !string.IsNullOrEmpty(windowsEnglish.Name)) + return windowsEnglish.Name; + + // Priority 2: Mac English (Platform 1, Language 0) + var macEnglish = NameTable.NameRecords.FirstOrDefault(x => + x.platformId == 1 && + x.languageID == 0 && + x.RecordType == recordType); + + if (macEnglish != null && !string.IsNullOrEmpty(macEnglish.Name)) + return macEnglish.Name; + + // Priority 3: Unicode English (Platform 0, Language 0) + var unicodeEnglish = NameTable.NameRecords.FirstOrDefault(x => + x.platformId == 0 && + x.languageID == 0 && + x.RecordType == recordType); + + if (unicodeEnglish != null && !string.IsNullOrEmpty(unicodeEnglish.Name)) + return unicodeEnglish.Name; + + // Priority 4: ANY Windows record of this type (fallback) + var anyWindows = NameTable.NameRecords.FirstOrDefault(x => + x.platformId == 3 && + x.RecordType == recordType); + + if (anyWindows != null && !string.IsNullOrEmpty(anyWindows.Name)) + return anyWindows.Name; + + // Priority 5: ANY record of this type (last resort) + var any = NameTable.NameRecords.FirstOrDefault(x => + x.RecordType == recordType); + + return any?.Name ?? string.Empty; + } + + internal void AddOrReplaceTable(T table) + where T : FontTableBase + { + if (IsReadOnly) + throw new InvalidOperationException( + $"Cannot modify a cached font instance. Table: {table.Name}. " + + "Use CreateSubset() or create a new OpenTypeFont instance."); + _localTableCache.AddOrReplace(table.Name, table); + + + var record = new TableRecord + { + Tag = new Tag(table.Name), + Length = (uint)table.GetLength(this), + Offset = 0, + Checksum = 0 + }; + + if (_tableRecords.ContainsKey(table.Name)) + { + _tableRecords.Remove(table.Name); + } + _tableRecords[table.Name] = record; + + } + + public OpenTypeFont CreateSubset(IEnumerable usedChars) + { + // Validate input + if (usedChars == null) + throw new ArgumentNullException(nameof(usedChars)); + + if (!usedChars.Any()) + throw new ArgumentException("Text cannot be empty", nameof(usedChars)); + + var subsetBuilder = new SubsetFontBuilder(); + + // Extract Unicode code points, correctly handling surrogate pairs. + // A string like "Hello 😀" contains 7 chars but 6 code points, + // because 😀 (U+1F600) is encoded as two UTF-16 surrogates. + var codePoints = CodePointUtil.ExtractCodePoints(usedChars); + + var newFont = subsetBuilder.CreateSubset(this, codePoints); + + var postProcessor = new SubsetPostProcessor(); + postProcessor.PostProcessSubset(newFont); + + return newFont; + } + + public static bool TryParseEnum(string value, out T result) where T : struct + { + try + { + result = (T)Enum.Parse(typeof(T), value, ignoreCase: true); + return true; + } + catch + { + result = default; + return false; + } + } + + internal uint SfntVersion { get; private set; } + + internal ushort NumTables { get; private set; } + + internal ushort SearchRange { get; private set; } + + internal ushort EntrySelector { get; private set; } + + internal ushort RangeShift { get; private set; } + + internal IDictionary TableRecords => _tableRecords; + + internal Dictionary PreprocessedPaddedTables { get; } = new Dictionary(); + + /// + /// For subset fonts: Maps original glyph IDs to new subset glyph IDs. + /// Null for non-subset fonts. + /// + public Dictionary SubsetGlyphMapping { get; internal set; } + + + /// + /// Total length (in bytes) of the underlying font stream. + /// Returns 0 if reader is null. + /// + internal long FileLength + { + get + { + if(_tblSettings == null || _tblSettings.TableReaderFactory == null) + { + return 0L; + } + return _tblSettings.TableReaderFactory.FontBytesLength; + } + } + + public byte[] GetTableData(string tag) + { + if (_tableRecords.TryGetValue(tag, out var record) && _tblSettings != null && _tblSettings.TableReaderFactory != null) + { + using var reader = _tblSettings.TableReaderFactory.CreateReader(); + if (reader != null && record.Offset > 0) + { + reader.BaseStream.Position = record.Offset; + return reader.ReadBytes((int)record.Length); + } + } + var ctx = new FontSerializationContext(this); + switch(tag) + { + case TableNames.Head: + return HeadTable.Serialize(ctx); + case TableNames.Loca: + return LocaTable.Serialize(ctx); + case TableNames.Cmap: + return CmapTable.Serialize(ctx); + case TableNames.Glyf: + return GlyfTable.Serialize(ctx); + case TableNames.Os2: + return Os2Table.Serialize(ctx); + case TableNames.Hhea: + return HheaTable.Serialize(ctx); + case TableNames.Maxp: + return MaxpTable.Serialize(ctx); + case TableNames.Hmtx: + return HmtxTable.Serialize(ctx); + case TableNames.Name: + return NameTable.Serialize(ctx); + case TableNames.Kern: + return KernTable.Serialize(ctx); + case TableNames.Post: + return PostTable.Serialize(ctx); + case TableNames.Gsub: + return GsubTable.Serialize(ctx); + case TableNames.Gpos: + return GposTable.Serialize(ctx); + case TableNames.Vhea: + return VheaTable?.Serialize(ctx); + case TableNames.Vmtx: + return VmtxTable?.Serialize(ctx); + default: + return null; + } + } + + public byte[] RawData + { + get + { + var reader = default(FontsBinaryReader); + if(_tblSettings != null && _tblSettings.TableReaderFactory != null) + { + reader = _tblSettings.TableReaderFactory.CreateReader(); + } + if (reader != null && reader.BaseStream != null) + { + long originalPosition = reader.BaseStream.Position; + try + { + reader.BaseStream.Position = 0; + return reader.ReadBytes((int)reader.BaseStream.Length); + } + finally + { + reader.BaseStream.Position = originalPosition; + } + } + return null; + } + } + + public byte[] Serialize() + { + var serializer = new OpenTypeFontSerializer(this); + return serializer.Serialize(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs new file mode 100644 index 0000000000..383263859a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs @@ -0,0 +1,453 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/13/2026 EPPlus Software AB Per-instance font engine. Replaces static OpenTypeFonts. + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontCache; +using EPPlus.Fonts.OpenType.FontResolver; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// An OpenType font engine instance. Owns its own configuration, resolver, and font cache — + /// two engines do not share parsed fonts and can have different configurations simultaneously. + /// Scanner-level data (file system listings, per-file FontFaceInfo) is shared globally + /// because that data describes the filesystem and is identical regardless of engine. + /// Configuration is set at construction time and is immutable for the lifetime of the engine. + /// To use a different configuration, create a new engine. + /// + public class OpenTypeFontEngine : IDisposable + { + private readonly object _syncRoot = new object(); + private readonly Dictionary _fontLocks = new Dictionary(); + + // Active resolver. Set at construction; never replaced. + private readonly IFontResolver _fontResolver; + + // Configuration snapshot. Held to support GetFontAvailability and similar queries. + private readonly EpplusFontConfiguration _configuration; + + // Per-engine cache of parsed fonts. + private readonly OpenTypeFontCache _fontCache = new OpenTypeFontCache(); + + // Thread-local TextShaper cache. Each thread gets its own dictionary, keyed by the engine + // instance to avoid collisions if multiple engines are used on the same thread. + // We use a ThreadStatic Dictionary> + // so each engine has its own per-thread shaper namespace. + [ThreadStatic] + private static Dictionary> _threadLocalShaperCaches; + + private bool _disposed; + + /// + /// Creates an engine with default configuration: no extra font directories, + /// system directories searched, no user fallbacks, default resolver. + /// + public OpenTypeFontEngine() + : this(null) + { + } + + /// + /// Creates an engine with the given configuration. + /// The configure callback runs once during construction and mutates the new + /// configuration. After the constructor returns, the configuration is fixed. + /// + /// + /// var engine = new OpenTypeFontEngine(cfg => + /// { + /// cfg.FontDirectories.Add(@"C:\MyApp\Fonts"); + /// cfg.SearchSystemDirectories = false; + /// cfg.FontFallbacks["Arial"] = new[] { "Helvetica" }; + /// }); + /// + public OpenTypeFontEngine(Action configure) + { + _configuration = new EpplusFontConfiguration(); + + if (configure != null) + { + configure(_configuration); + } + + // If the user installed a custom resolver, use it as-is. Otherwise build a + // DefaultFontResolver from the configuration. + var userResolver = _configuration.FontResolver; + if (userResolver != null) + { + _fontResolver = userResolver; + } + else + { + _fontResolver = new DefaultFontResolver( + fontDirectories: _configuration.FontDirectories, + searchSystemDirectories: _configuration.SearchSystemDirectories, + config: _configuration); + } + } + + // ----------------------------------------------------------------------------------------- + // Public API + // ----------------------------------------------------------------------------------------- + + /// + /// When true, GetTextShaper throws if the requested font cannot be resolved to an exact match, + /// even though a fallback was found. Default is false: rendering trusts the fallback chain + /// (which always resolves to at least the embedded font) and never throws. Set to true only + /// for diagnostics or validation where a missing exact font should surface as an error. + /// + public bool RequireExactFont { get; set; } = false; + //public FontAvailability FallBackAvailablility = FontAvailability.Exact; + + /// + /// Gets a TextShaper for the given font, reusing a thread-local cached instance. + /// The underlying OpenTypeFont is shared within this engine (but not between engines), + /// while each thread gets its own TextShaper instance to avoid locking. + /// Returns null if the font cannot be resolved. + /// + public TextShaper GetTextShaper(string fontName, FontSubFamily subFamily = FontSubFamily.Regular) + { + ThrowIfDisposed(); + if (fontName == null) + throw new ArgumentNullException("fontName"); + + var perEngineMap = GetOrCreateThreadLocalShaperMap(); + + string key = BuildCacheKey(fontName, subFamily); + + TextShaper shaper; + if (!perEngineMap.TryGetValue(key, out shaper)) + { + var font = LoadFont(fontName, subFamily); + if (font == null) + return null; + + if (RequireExactFont) + { + var availability = GetFontAvailability(fontName, subFamily); + if (availability != FontAvailability.Exact) + { + throw new FileNotFoundException( + $"Could not find Font: {fontName} {subFamily}. Resolved via fallback to: {font.GetEnglishFontFamilyName()} {font.SubFamily}."); + } + } + + shaper = new TextShaper(this, font); + perEngineMap[key] = shaper; + } + + return shaper; + } + + public TextLayoutEngine GetTextLayoutEngine(string fontName, FontSubFamily subFamily = FontSubFamily.Regular) + { + var shaper = GetTextShaper(fontName, subFamily); + return new TextLayoutEngine(this, shaper); + } + public TextLayoutEngine GetTextLayoutEngineForFont(IFontFormatBase font) + { + var shaper = GetShaperForFont(font); + return new TextLayoutEngine(this, shaper); + } + + public ITextShaper GetShaperForFont(IFontFormatBase font) + { + return GetTextShaper(font.Family, font.SubFamily); + } + + public TextLayoutEngine GetTextLayoutEngineForFont(MeasurementFont font) + { + var shaper = GetShaperForFont(font); + return new TextLayoutEngine(this, shaper); + } + + public ITextShaper GetShaperForFont(MeasurementFont font) + { + return GetTextShaper(font.FontFamily, GetFontSubFamily(font.Style)); + } + + public static FontSubFamily GetFontSubFamily(MeasurementFontStyles style) + { + if ((style & (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) == + (MeasurementFontStyles.Bold | MeasurementFontStyles.Italic)) + { + return FontSubFamily.BoldItalic; + } + else if ((style & MeasurementFontStyles.Bold) == MeasurementFontStyles.Bold) + { + return FontSubFamily.Bold; + } + else if ((style & MeasurementFontStyles.Italic) == MeasurementFontStyles.Italic) + { + return FontSubFamily.Italic; + } + + return FontSubFamily.Regular; + } + + /// + /// Clears this engine's parsed-font cache, per-font locks, and the calling thread's + /// TextShaper cache for this engine. Does not affect scanner-level caches (which are + /// global and reflect filesystem state, not engine configuration). + /// + public void ClearFontCache() + { + ThrowIfDisposed(); + lock (_syncRoot) + { + _fontCache.Clear(); + _fontLocks.Clear(); + } + + // Clear this engine's shaper cache for the calling thread. + // Other threads' caches will be lazily rebuilt on next use. + if (_threadLocalShaperCaches != null) + _threadLocalShaperCaches.Remove(this); + } + + // ----------------------------------------------------------------------------------------- + // Font loading + // ----------------------------------------------------------------------------------------- + + /// + /// Loads a font by name and subfamily, with thread-safe caching within this engine. + /// Returns null if the font cannot be resolved. + /// + public OpenTypeFont LoadFont( + string fontName, + FontSubFamily subFamily = FontSubFamily.Regular, + bool ignoreCache = false) + { + ThrowIfDisposed(); + + if (ignoreCache) + return ResolveAndCreate(_fontResolver, fontName, subFamily); + + string lockKey = BuildCacheKey(fontName, subFamily); + object fontLock; + lock (_syncRoot) + { + if (!_fontLocks.TryGetValue(lockKey, out fontLock)) + { + fontLock = new object(); + _fontLocks[lockKey] = fontLock; + } + } + + lock (fontLock) + { + var cached = _fontCache.GetFromCache(lockKey); + if (cached != null && cached.Font != null && cached.IsLoaded) + { + cached.Font.EnsureFullyLoaded(); + return cached.Font; + } + + _fontCache.BeginCache(lockKey); + + var font = ResolveAndCreate(_fontResolver, fontName, subFamily); + if (font == null) + return null; + + font.EnsureFullyLoaded(); + font.IsReadOnly = true; + _fontCache.AddToCache(font, lockKey); + return font; + } + } + + /// + /// Returns all available font faces as fully loaded OpenTypeFont instances. + /// Skips corrupt or unreadable fonts, but logs detailed information for diagnostics. + /// This method is NOT cached and may take significant time to complete. + /// Note: takes fontDirectories as a parameter; this is a diagnostic / discovery API + /// independent of the engine's configured resolver. + /// + public List GetAllBaseFontData( + List fontDirectories, + bool searchSystemDirectories = true, + FontFormat? formatTarget = null) + { + ThrowIfDisposed(); + + var locations = DefaultFontLocations.GetLocationsCollection(fontDirectories, searchSystemDirectories); + var faces = FontScannerV2.EnumerateAllFaces(locations); + + var result = new List(faces.Count); + var failures = 0; + + foreach (var face in faces) + { + if (formatTarget.HasValue) + { + string ext = Path.GetExtension(face.FilePath); + if (!string.IsNullOrEmpty(ext)) + { + ext = ext.ToLowerInvariant(); + var format = (ext == ".otf" || ext == ".cff") + ? FontFormat.Otf + : FontFormat.Ttf; + + if (format != formatTarget.Value) + continue; + } + } + + try + { + var font = new OpenTypeFont(File.ReadAllBytes(face.FilePath)); + font.EnsureFullyLoaded(); + result.Add(font); + } + catch (Exception ex) + { + failures++; + System.Diagnostics.Debug.WriteLine( + string.Format("[OpenTypeFontEngine] Failed to load font: {0} => {1}: {2}", + face.FilePath, ex.GetType().Name, ex.Message)); + } + } + + if (failures > 0) + System.Diagnostics.Debug.WriteLine( + string.Format("[OpenTypeFontEngine] {0} font(s) failed to load.", failures)); + + return result; + } + + /// + /// Creates an OpenTypeFont directly from raw font bytes. + /// Font format (TTF/OTF) is detected automatically from the SFNT header. + /// Independent of engine configuration — does not consult the resolver or cache. + /// + public OpenTypeFont GetFromBytes(byte[] bytes) + { + if (bytes == null) + throw new ArgumentNullException("bytes"); + + var font = new OpenTypeFont(bytes); + font.EnsureFullyLoaded(); + return font; + } + + /// + /// Checks whether a font is available in this engine's configured font system. + /// Returns if the exact family and subfamily exist, + /// if the family exists but not in the requested + /// subfamily, and otherwise. + /// + /// If the engine has a custom resolver that implements , + /// the call delegates to the resolver. Otherwise it probes via , + /// which can only distinguish "found" from "not found" — never . + /// + public FontAvailability GetFontAvailability( + string fontName, + FontSubFamily subFamily = FontSubFamily.Regular) + { + ThrowIfDisposed(); + if (fontName == null) + throw new ArgumentNullException("fontName"); + + var provider = _fontResolver as IFontAvailabilityProvider; + if (provider != null) + return provider.GetFontAvailability(fontName, subFamily); + + // Fallback: probe via ResolveFont. Cannot distinguish FamilyOnly. + return _fontResolver.ResolveFont(fontName, subFamily) != null + ? FontAvailability.Exact + : FontAvailability.NotFound; + } + + // ----------------------------------------------------------------------------------------- + // Internal helpers + // ----------------------------------------------------------------------------------------- + + /// + /// Returns the configured fallback chain for the given Unicode script, or null if + /// none is configured. An empty array means fallback is explicitly disabled for the + /// script. Used by DefaultFontProvider to look up script-level glyph fallbacks. + /// + internal string[] GetScriptFallback(UnicodeScript script) + { + return _configuration.GetScriptFallback(script); + } + + internal static string BuildCacheKey(string fontName, FontSubFamily subFamily) + { + return string.Format("{0}_{1}", fontName, subFamily); + } + + private static OpenTypeFont ResolveAndCreate(IFontResolver resolver, string fontName, FontSubFamily subFamily) + { + var bytes = resolver.ResolveFont(fontName, subFamily); + if (bytes == null) + return null; + + return new OpenTypeFont(bytes); + } + + private Dictionary GetOrCreateThreadLocalShaperMap() + { + // [ThreadStatic] field initializers only run on the primary thread. + // All other threads see null and must initialize on first use. + if (_threadLocalShaperCaches == null) + _threadLocalShaperCaches = new Dictionary>(); + + Dictionary map; + if (!_threadLocalShaperCaches.TryGetValue(this, out map)) + { + map = new Dictionary(); + _threadLocalShaperCaches[this] = map; + } + return map; + } + + internal static List GetLocationsCollection( + IEnumerable fontDirectories, + bool searchSystemDirectories) + { + return DefaultFontLocations.GetLocationsCollection(fontDirectories, searchSystemDirectories); + } + + private void ThrowIfDisposed() + { + if (_disposed) + throw new ObjectDisposedException("OpenTypeFontEngine"); + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + + lock (_syncRoot) + { + _fontCache.Clear(); + _fontLocks.Clear(); + } + + // Best-effort cleanup of this engine's shaper map on the disposing thread. + // Maps on other threads will be cleaned up when those threads next touch their map, + // since they will see no entry for this engine and rebuild fresh. The lingering + // entries are small (empty dictionaries) and held only by the disposing-time references. + if (_threadLocalShaperCaches != null) + _threadLocalShaperCaches.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFontFactory.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFontFactory.cs new file mode 100644 index 0000000000..ff1668b69e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFontFactory.cs @@ -0,0 +1,44 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using System.IO; + +namespace EPPlus.Fonts.OpenType +{ + internal static class OpenTypeFontFactory + { + public static OpenTypeFont CreateFromFace(FontFaceInfo face) + { + byte[] fontData = File.ReadAllBytes(face.FilePath); + + if (face.OffsetInFile > 0) // Font inside TTC + { + // Pass the start offset to the constructor + // This tells OpenTypeFont where this font's table directory starts + return new OpenTypeFont(fontData, face.OffsetInFile); + } + else // Regular TTF/OTF + { + var format = Path.GetExtension(face.FilePath).ToLowerInvariant() == ".otf" + ? FontFormat.Otf + : FontFormat.Ttf; + return new OpenTypeFont(fontData); + } + } + + public static OpenTypeFont CreateFromBytes(byte[] bytes) + { + return new OpenTypeFont(bytes); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFontSerializer.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFontSerializer.cs new file mode 100644 index 0000000000..b49fc02a58 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFontSerializer.cs @@ -0,0 +1,133 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType +{ + + internal class OpenTypeFontSerializer + { + private readonly OpenTypeFont _font; + + public OpenTypeFontSerializer(OpenTypeFont font) + { + _font = font ?? throw new ArgumentNullException(nameof(font)); + } + + public byte[] Serialize() + { + using (var stream = new MemoryStream()) + using (var writer = new FontsBinaryWriter(stream)) + { + var sortedTags = _font.TableRecords.Keys.OrderBy(k => k).ToList(); + int numTables = sortedTags.Count; + + // 1. First pass: serialize all tables to get their actual bytes + var tableBytes = new Dictionary(); + foreach (var tag in sortedTags) + { + byte[] data; + if (_font.PreprocessedPaddedTables != null && + _font.PreprocessedPaddedTables.TryGetValue(tag, out var cachedBytes)) + { + data = cachedBytes; + } + else + { + data = _font.GetTableData(tag); + // Pad to 4-byte boundary + int rawLen = data.Length; + int paddedLen = (rawLen + 3) & ~3; + if (paddedLen > rawLen) + { + Array.Resize(ref data, paddedLen); + } + } + tableBytes[tag] = data; + } + + // 2. Calculate correct offsets + // Header = 12 bytes, each table record = 16 bytes + uint currentOffset = (uint)(12 + numTables * 16); + + var newRecords = new List(); + foreach (var tag in sortedTags) + { + var data = tableBytes[tag]; + var originalRecord = _font.TableRecords[tag]; + + var newRecord = new TableRecord + { + Tag = new Tag(tag), + Checksum = originalRecord.Checksum, // Keep original checksum for now + Offset = currentOffset, + Length = originalRecord.Length + }; + newRecords.Add(newRecord); + + // Move to next table (already padded) + currentOffset += (uint)data.Length; + } + + // 3. Write sfnt header + WriteSfntHeader(writer, numTables); + + // 4. Write table directory with CORRECT offsets + foreach (var record in newRecords) + { + WriteTableRecord(writer, record); + } + + // 5. Write table data + foreach (var tag in sortedTags) + { + writer.Write(tableBytes[tag]); + } + + return stream.ToArray(); + } + } + + private void WriteSfntHeader(FontsBinaryWriter writer, int numTables) + { + writer.WriteUInt32BigEndian(0x00010000); // sfntVersion for TrueType + writer.WriteUInt16BigEndian((ushort)numTables); + + int maxPower2 = 1; + int entrySelector = 0; + while (maxPower2 * 2 <= numTables) + { + maxPower2 *= 2; + entrySelector++; + } + ushort searchRange = (ushort)(maxPower2 * 16); + ushort rangeShift = (ushort)(numTables * 16 - searchRange); + + writer.WriteUInt16BigEndian(searchRange); + writer.WriteUInt16BigEndian((ushort)entrySelector); + writer.WriteUInt16BigEndian(rangeShift); + } + + private void WriteTableRecord(FontsBinaryWriter writer, TableRecord record) + { + writer.Write(record.Tag.ToBytes()); // 4 bytes ASCII + writer.WriteUInt32BigEndian(record.Checksum); + writer.WriteUInt32BigEndian(record.Offset); + writer.WriteUInt32BigEndian(record.Length); + } + } + +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFonts.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFonts.cs new file mode 100644 index 0000000000..4a74778c1d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFonts.cs @@ -0,0 +1,176 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/10/2026 EPPlus Software AB Fix threading issue with global lock + 01/23/2026 EPPlus Software AB Improved thread-safety with per-font locking + 02/26/2026 EPPlus Software AB Moved caching from DefaultFontResolver to here + 02/27/2026 EPPlus Software AB Replaced Configure overloads with IEpplusFontConfiguration + 03/20/2026 EPPlus Software AB Added thread-local TextShaper cache + 05/06/2026 EPPlus Software AB Transactional Configure; single resolver, single cache key + 05/13/2026 EPPlus Software AB Reduced to a thin facade over a singleton OpenTypeFontEngine + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Scanner; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Static facade for the OpenType font system. Delegates to a singleton + /// instance for backward compatibility with + /// callers that have not yet been migrated to per-instance engine usage. + /// + /// New code should prefer creating and owning an OpenTypeFontEngine directly. + /// + public static class OpenTypeFonts + { + private static readonly object _syncRoot = new object(); + private static OpenTypeFontEngine _default = new OpenTypeFontEngine(); + + // ----------------------------------------------------------------------------------------- + // Configuration (mutates the singleton engine) + // ----------------------------------------------------------------------------------------- + + /// + /// Reconfigures the singleton font engine used by this static facade. + /// Internally creates a new with the supplied + /// configuration and replaces the previous singleton. The previous engine is disposed, + /// invalidating any caches built against it. + /// + /// This method exists for source compatibility with callers that have not yet been + /// migrated to per-instance engine usage. New code should create its own + /// instead. + /// + public static void Configure(Action configure) + { + if (configure == null) + throw new ArgumentNullException("configure"); + + OpenTypeFontEngine oldEngine; + lock (_syncRoot) + { + oldEngine = _default; + _default = new OpenTypeFontEngine(configure); + } + + // Dispose the old engine outside the lock. Any caller still holding a reference + // to it (e.g. via GetTextShaper) will get an ObjectDisposedException on next use, + // which is the intended signal that configuration changed underneath them. + try { oldEngine.Dispose(); } catch { /* swallow - best effort */ } + } + + // ----------------------------------------------------------------------------------------- + // Delegating API + // ----------------------------------------------------------------------------------------- + + public static TextShaper GetTextShaper(string fontName, FontSubFamily subFamily = FontSubFamily.Regular) + { + return _default.GetTextShaper(fontName, subFamily); + } + + public static TextLayoutEngine GetTextLayoutEngine(string fontName, FontSubFamily subFamily = FontSubFamily.Regular) + { + return _default.GetTextLayoutEngine(fontName, subFamily); + } + + + public static TextLayoutEngine GetTextLayoutEngineForFont(IFontFormatBase font) + { + return _default.GetTextLayoutEngineForFont(font); + } + + public static TextLayoutEngine GetTextLayoutEngineForFont(MeasurementFont font) + { + return _default.GetTextLayoutEngineForFont(font); + } + + public static ITextShaper GetShaperForFont(MeasurementFont font) + { + return _default.GetShaperForFont(font); + } + + public static ITextShaper GetShaperForFont(IFontFormatBase font) + { + return _default.GetShaperForFont(font); + } + + public static FontSubFamily GetFontSubFamily(MeasurementFontStyles style) + { + return OpenTypeFontEngine.GetFontSubFamily(style); + } + + public static void ClearFontCache() + { + _default.ClearFontCache(); + } + + public static OpenTypeFont LoadFont( + string fontName, + FontSubFamily subFamily = FontSubFamily.Regular, + bool ignoreCache = false) + { + return _default.LoadFont(fontName, subFamily, ignoreCache); + } + + /// + /// Overload preserved for source compatibility with callers that pass fontDirectories. + /// The directories argument is IGNORED - to add directories permanently, configure the + /// engine via or create your own . + /// + [Obsolete("Pass font directories through OpenTypeFonts.Configure(cfg => cfg.FontDirectories.Add(...)) or use OpenTypeFontEngine directly. The directories argument is ignored.", false)] + public static OpenTypeFont LoadFont( + string fontName, + FontSubFamily subFamily, + IEnumerable fontDirectories, + bool searchSystemDirectories = true, + bool ignoreCache = false) + { + return _default.LoadFont(fontName, subFamily, ignoreCache); + } + + public static List GetAllBaseFontData( + List fontDirectories, + bool searchSystemDirectories = true, + FontFormat? formatTarget = null) + { + return _default.GetAllBaseFontData(fontDirectories, searchSystemDirectories, formatTarget); + } + + public static OpenTypeFont GetFromBytes(byte[] bytes) + { + return _default.GetFromBytes(bytes); + } + + public static FontAvailability GetFontAvailability( + string fontName, + FontSubFamily subFamily = FontSubFamily.Regular) + { + return _default.GetFontAvailability(fontName, subFamily); + } + + internal static string BuildCacheKey(string fontName, FontSubFamily subFamily) + { + return OpenTypeFontEngine.BuildCacheKey(fontName, subFamily); + } + + internal static List GetLocationsCollection( + IEnumerable fontDirectories, + bool searchSystemDirectories) + { + return OpenTypeFontEngine.GetLocationsCollection(fontDirectories, searchSystemDirectories); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Bold.ttf b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Bold.ttf new file mode 100644 index 0000000000..05861d99f8 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Bold.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-BoldItalic.ttf b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-BoldItalic.ttf new file mode 100644 index 0000000000..ab2d419998 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-BoldItalic.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Italic.ttf b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Italic.ttf new file mode 100644 index 0000000000..daf0f93f52 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Italic.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Regular.ttf b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Regular.ttf new file mode 100644 index 0000000000..f1c9c6d934 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/ArchivoNarrow-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/NotoEmoji-Regular.ttf b/src/EPPlus.Fonts.OpenType/Resources/NotoEmoji-Regular.ttf new file mode 100644 index 0000000000..b50618f0f5 Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/NotoEmoji-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/NotoSansMath-Regular.ttf b/src/EPPlus.Fonts.OpenType/Resources/NotoSansMath-Regular.ttf new file mode 100644 index 0000000000..7062ca131d Binary files /dev/null and b/src/EPPlus.Fonts.OpenType/Resources/NotoSansMath-Regular.ttf differ diff --git a/src/EPPlus.Fonts.OpenType/Resources/THIRD_PARTY_LICENSES.txt b/src/EPPlus.Fonts.OpenType/Resources/THIRD_PARTY_LICENSES.txt new file mode 100644 index 0000000000..787f89b3a7 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Resources/THIRD_PARTY_LICENSES.txt @@ -0,0 +1,30 @@ +Noto Emoji Font +Copyright 2013 Google LLC +Licensed under the SIL Open Font License, Version 1.1 + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is available with a FAQ at: https://scripts.sil.org/OFL + +The font and its source code are available at: +https://github.com/googlefonts/noto-emoji + + +Noto Sans Math Font +Copyright 2022 The Noto Project Authors (https://github.com/notofonts/math) +Licensed under the SIL Open Font License, Version 1.1 + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is available with a FAQ at: https://openfontlicense.org + +The font and its source code are available at: +https://github.com/notofonts/math + +Archivo Narrow Font +Copyright 2011 The Archivo Project Authors (https://github.com/Omnibus-Type/ArchivoNarrow) +Licensed under the SIL Open Font License, Version 1.1 + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is available with a FAQ at: https://openfontlicense.org + +The font and its source code are available at: +https://github.com/Omnibus-Type/ArchivoNarrow \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontFileReader.cs b/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontFileReader.cs new file mode 100644 index 0000000000..c6c40c8e98 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontFileReader.cs @@ -0,0 +1,145 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 03/02/2026 EPPlus Software AB TTC support (extracted from DefaultFontResolver) + 05/06/2026 EPPlus Software AB Moved into IFontFileReader implementation + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Default file-system implementation of IFontFileReader. + /// Reads font bytes directly from disk. TTC (TrueType Collection) files are handled + /// transparently — the correct font is extracted and returned as standalone TTF bytes. + /// + internal sealed class DefaultFontFileReader : IFontFileReader + { + public byte[] ReadFontBytes(FontFaceInfo face) + { + byte[] fileBytes = File.ReadAllBytes(face.FilePath); + + if (face.OffsetInFile > 0) + return ExtractTtcFont(fileBytes, face.OffsetInFile); + + return fileBytes; + } + + /// + /// Extracts a single TTF font from a TTC collection file. + /// Reads the font's table directory at the given offset, copies all referenced table data, + /// and returns a new valid standalone TTF byte array with recalculated offsets. + /// + /// Raw bytes of the TTC file. + /// Byte offset within the TTC file where the target font's SFNT header begins. + /// Standalone TTF bytes for the font at the given offset. + private static byte[] ExtractTtcFont(byte[] ttcBytes, long offset) + { + using (var ms = new MemoryStream(ttcBytes)) + using (var reader = new BinaryReader(ms)) + { + // Read SFNT header at offset + ms.Position = offset; + uint sfntVersion = ReadUInt32BE(reader); + ushort numTables = ReadUInt16BE(reader); + ms.Position += 6; // skip searchRange, entrySelector, rangeShift + + // Read table records from the font's table directory + var tags = new string[numTables]; + var checksums = new uint[numTables]; + var srcOffsets = new uint[numTables]; + var lengths = new uint[numTables]; + + for (int i = 0; i < numTables; i++) + { + byte[] tagBytes = reader.ReadBytes(4); + tags[i] = new string(new char[] { (char)tagBytes[0], (char)tagBytes[1], (char)tagBytes[2], (char)tagBytes[3] }); + checksums[i] = ReadUInt32BE(reader); + srcOffsets[i] = ReadUInt32BE(reader); + lengths[i] = ReadUInt32BE(reader); + } + + // Calculate output size: SFNT header (12) + table directory (16 * n) + aligned table data + int directorySize = 12 + numTables * 16; + int totalSize = directorySize; + for (int i = 0; i < numTables; i++) + totalSize += (int)((lengths[i] + 3u) & ~3u); + + byte[] result = new byte[totalSize]; + + using (var outMs = new MemoryStream(result)) + using (var writer = new BinaryWriter(outMs)) + { + // Write SFNT header + WriteUInt32BE(writer, sfntVersion); + WriteUInt16BE(writer, numTables); + + // Recompute searchRange, entrySelector, rangeShift per spec + int pot = 1, log2 = 0; + while (pot * 2 <= numTables) { pot *= 2; log2++; } + WriteUInt16BE(writer, (ushort)(pot * 16)); // searchRange + WriteUInt16BE(writer, (ushort)log2); // entrySelector + WriteUInt16BE(writer, (ushort)((numTables - pot) * 16)); // rangeShift + + // Calculate new table offsets (table data starts right after directory) + uint[] newOffsets = new uint[numTables]; + uint newOffset = (uint)directorySize; + for (int i = 0; i < numTables; i++) + { + newOffsets[i] = newOffset; + newOffset += (lengths[i] + 3u) & ~3u; + } + + // Write table directory with updated offsets + for (int i = 0; i < numTables; i++) + { + foreach (char c in tags[i]) writer.Write((byte)c); + WriteUInt32BE(writer, checksums[i]); + WriteUInt32BE(writer, newOffsets[i]); + WriteUInt32BE(writer, lengths[i]); + } + + // Copy table data from TTC into the new buffer at recalculated offsets + for (int i = 0; i < numTables; i++) + { + System.Array.Copy(ttcBytes, srcOffsets[i], result, newOffsets[i], lengths[i]); + } + } + + return result; + } + } + + private static uint ReadUInt32BE(BinaryReader r) + { + byte[] b = r.ReadBytes(4); + return (uint)(b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]); + } + + private static ushort ReadUInt16BE(BinaryReader r) + { + byte[] b = r.ReadBytes(2); + return (ushort)(b[0] << 8 | b[1]); + } + + private static void WriteUInt32BE(BinaryWriter w, uint v) + { + w.Write((byte)(v >> 24)); + w.Write((byte)(v >> 16)); + w.Write((byte)(v >> 8)); + w.Write((byte)v); + } + + private static void WriteUInt16BE(BinaryWriter w, ushort v) + { + w.Write((byte)(v >> 8)); + w.Write((byte)v); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontScanner.cs b/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontScanner.cs new file mode 100644 index 0000000000..5b91bc9363 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/DefaultFontScanner.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +internal sealed class DefaultFontScanner : IFontScanner +{ + public FontFaceInfo FindBestMatch( + IEnumerable additionalDirectories, + string familyName, + FontSubFamily desiredStyle, + bool searchSystemDirectories) + { + return FontScannerV2.FindBestMatch( + additionalDirectories, familyName, desiredStyle, searchSystemDirectories); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontDirectoryCache.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontDirectoryCache.cs new file mode 100644 index 0000000000..ebecb7f898 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontDirectoryCache.cs @@ -0,0 +1,136 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Thread-safe cache for directory listings of font files. + /// Prevents repeated (and expensive) Directory.GetFiles() calls on the same font directories. + /// Especially important for system font folders (C:\Windows\Fonts) with thousands of files. + /// Fully compatible with .NET 3.5. + /// + internal static class FontDirectoryCache + { + private static readonly Dictionary _cache + = new Dictionary(StringComparer.OrdinalIgnoreCase); + + private static readonly object _lock = new object(); + + private class CachedDirectoryInfo + { + public string[] FontFiles; // List of .ttf, .otf, .ttc files + public DateTime LastCheckTime; // When we last validated the cache + public long DirectoryTicks; // Directory.GetLastWriteTimeUtc().Ticks + } + + /// + /// Returns cached list of font files in the given directory. + /// If the directory has not changed since last check, returns cached result. + /// Otherwise performs a fresh scan and updates the cache. + /// + public static string[] GetFontFiles(string directory) + { + if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory)) + return new string[0]; + + lock (_lock) + { + CachedDirectoryInfo cached; + bool needRefresh = true; + + if (_cache.TryGetValue(directory, out cached)) + { + try + { + // Simple but effective: compare directory write time + long currentTicks = Directory.GetLastWriteTimeUtc(directory).Ticks; + if (currentTicks == cached.DirectoryTicks) + needRefresh = false; + } + catch (UnauthorizedAccessException) { /* ignore */ } + catch (IOException) { /* ignore */ } + catch (SecurityException) { /* ignore */ } + } + + if (!needRefresh) + return cached.FontFiles; + + // Perform fresh scan + string[] files = ScanDirectoryForFonts(directory); + + // Update cache + cached = new CachedDirectoryInfo + { + FontFiles = files, + LastCheckTime = DateTime.UtcNow, + DirectoryTicks = Directory.GetLastWriteTimeUtc(directory).Ticks + }; + + _cache[directory] = cached; + return files; + } + } + + /// + /// Performs the actual directory scan for font files. + /// Separated for clarity and testability. + /// + private static string[] ScanDirectoryForFonts(string directory) + { + try + { + string[] allFiles = Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories); + List fontFiles = new List(allFiles.Length); + + foreach (string file in allFiles) + { + string ext = Path.GetExtension(file); + if (ext != null) + { + ext = ext.ToLowerInvariant(); + if (ext == ".ttf" || ext == ".otf" || ext == ".ttc") + { + fontFiles.Add(file); + } + } + } + + return fontFiles.ToArray(); + } + catch (UnauthorizedAccessException) { return new string[0]; } + catch (IOException) { return new string[0]; } + catch (SecurityException) { return new string[0]; } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine("[FontDirectoryCache] Failed to scan directory: " + directory + " → " + ex.Message); + return new string[0]; + } + } + + /// + /// Clears the entire directory cache. + /// Call when font folders may have changed or during application reset. + /// + public static void Clear() + { + lock (_lock) + { + _cache.Clear(); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfo.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfo.cs new file mode 100644 index 0000000000..864b597125 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfo.cs @@ -0,0 +1,146 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 05/06/2026 EPPlus Software AB Added Clone() to support thread-safe FindBestMatch + *************************************************************************************************/ +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Lightweight representation of a single font face. Used for caching and lookup during + /// font scanning. Contains no open streams or heavy objects – only metadata and table directory. + /// + /// + /// Instances cached by FontScannerCache are shared between callers. Any code that needs to + /// set per-query state (such as IsExactMatch) must call Clone() first and mutate the copy — + /// mutating the cached instance is not thread-safe. + /// + public class FontFaceInfo + { + /// + /// Full path to the font file on disk. + /// + public string FilePath { get; internal set; } + + /// + /// The detected format of the containing file. + /// + public FontFormat Format { get; internal set; } + + /// + /// Offset within the file where this font face starts. + /// 0 for regular TTF/OTF files, greater than 0 for faces inside TTC collections. + /// + public long OffsetInFile { get; internal set; } + + /// + /// File modification time used for cache invalidation. + /// + public DateTime LastWriteTimeUtc { get; internal set; } + + /// + /// Font family name (e.g. "Arial", "Roboto"). + /// + public string FamilyName { get; internal set; } + + /// + /// Font subfamily name from name table (e.g. "Regular", "Bold Italic"). + /// + public string SubfamilyName { get; internal set; } + + /// + /// Full font Name from name table (e.g. "Roboto Regular") + /// + public string FullFontName { get; internal set; } + + /// + /// Normalized subfamily as enum. + /// + public FontSubFamily Subfamily { get; internal set; } + + public ushort FsSelection { get; internal set; } + + /// + /// True if this face was returned from a query that matched it exactly (by family name + /// and subfamily). This is per-query state — never set on a cached instance directly; + /// always Clone() first. + /// + public bool IsExactMatch { get; internal set; } + + /// + /// True if this face is a variable font (i.e. the file contains an 'fvar' table). + /// A variable font can only be relied upon to deliver its default named instance unless + /// the variation tables are interpolated, which this library does not yet do. Matching + /// therefore treats a variable face as capable of delivering only its default subfamily. + /// + public bool IsVariable { get; internal set; } + + /// + /// Table directory for this face. + /// + public Dictionary TableRecords { get; internal set; } + + /// + /// Unique cache key: FilePath + "|" + OffsetInFile + /// + internal string CacheKey + { + get { return FilePath + "|" + OffsetInFile; } + } + + internal FontFaceInfo() + { + TableRecords = new Dictionary(StringComparer.Ordinal); + } + + /// + /// Creates a shallow copy of this instance. All value-type and string fields are copied; + /// the TableRecords dictionary is shared by reference because it is populated once during + /// scanning and never mutated afterwards. + /// + /// + /// Used by FontScannerV2.FindBestMatch to avoid mutating the cached instance with + /// per-query state (IsExactMatch). Mutating a cached instance would cause a race + /// condition between parallel callers. + /// + internal FontFaceInfo Clone() + { + return new FontFaceInfo + { + FilePath = FilePath, + Format = Format, + OffsetInFile = OffsetInFile, + LastWriteTimeUtc = LastWriteTimeUtc, + FamilyName = FamilyName, + SubfamilyName = SubfamilyName, + FullFontName = FullFontName, + Subfamily = Subfamily, + FsSelection = FsSelection, + IsExactMatch = IsExactMatch, + IsVariable = IsVariable, // carry variable-font flag into per-query copy + TableRecords = TableRecords, // shared by reference — never mutated post-scan + }; + } + + public override string ToString() + { + return string.Format("{0} {1} → {2}{3}", + FamilyName, + SubfamilyName, + Path.GetFileName(FilePath), + OffsetInFile > 0 ? " [TTC]" : ""); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfoExtensions.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfoExtensions.cs new file mode 100644 index 0000000000..16535029e2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontFaceInfoExtensions.cs @@ -0,0 +1,45 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; + +// File: FontFaceInfoExtensions.cs +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Helper extensions to make tests as clean as before. + /// + public static class FontFaceInfoExtensions + { + /// + /// Returns the raw bytes of a font table – exactly like the old ScannedFont.GetTableBytes(). + /// Thread-safe, fast, and zero memory leaks. + /// + public static byte[] GetTableBytes(this FontFaceInfo face, string tag) + { + if (face == null) throw new ArgumentNullException(nameof(face)); + if (!face.TableRecords.TryGetValue(tag, out var record)) + throw new ArgumentException($"Table '{tag}' not found in font {face.FilePath}"); + + using var fs = new FileStream(face.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read); + fs.Position = face.OffsetInFile + record.Offset; + + var buffer = new byte[record.Length]; + int read = fs.Read(buffer, 0, buffer.Length); + if (read != buffer.Length) + throw new IOException($"Could not read entire table '{tag}' from {face.FilePath}"); + + return buffer; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontFormat.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontFormat.cs new file mode 100644 index 0000000000..ee68656394 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontFormat.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Scanner +{ + + /// + /// Defines the supported font file formats that can be parsed or identified by the library. + /// + public enum FontFormat + { + /// + /// TrueType Font (.ttf) — a widely used font format developed by Apple and Microsoft. + /// + /// TrueType Collection (.ttc) — a container format that holds multiple TrueType fonts in a single file. + /// + /// OpenType Font (.otf) — an extension of TrueType that supports advanced typographic features and PostScript outlines. + /// + Otf = 2 + } +} diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontScannerCache.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerCache.cs new file mode 100644 index 0000000000..07fb90e4e4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerCache.cs @@ -0,0 +1,92 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Thread-safe cache for scanned font faces. + /// Key = FilePath|OffsetInFile, Value = FontFaceInfo + /// Automatically invalidates entries if file has been modified. + /// + internal static class FontScannerCache + { + private static readonly Dictionary _cache + = new Dictionary(StringComparer.OrdinalIgnoreCase); + + private static readonly object _syncLock = new object(); + + /// + /// Returns cached FontFaceInfo or creates and caches a new one using the provided factory. + /// + public static FontFaceInfo GetOrAdd(string filePath, long offset, Func factory) + { + string key = filePath + "|" + offset; + + lock (_syncLock) + { + if (_cache.TryGetValue(key, out FontFaceInfo info)) + { + // Invalidate if file was modified + try + { + DateTime current = File.GetLastWriteTimeUtc(filePath); + if (current != info.LastWriteTimeUtc) + { + _cache.Remove(key); + } + else + { + return info; + } + } + catch + { + // File deleted or access denied → remove from cache + _cache.Remove(key); + } + } + + info = factory(filePath, offset); + _cache[key] = info; + return info; + } + } + + /// + /// Clears the entire cache. Used during testing and when font folders change. + /// + public static void Clear() + { + lock (_syncLock) + { + _cache.Clear(); + } + } + + /// + /// Returns all cached faces (for diagnostics or full enumeration). + /// + public static List GetAll() + { + lock (_syncLock) + { + return new List(_cache.Values); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.Ttc.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.Ttc.cs new file mode 100644 index 0000000000..b27363da58 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.Ttc.cs @@ -0,0 +1,110 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2026 EPPlus Software AB OpenType font implementation + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + internal static partial class FontScannerV2 + { + /// + /// Scans a TrueType Collection (.ttc) file and returns all contained font faces. + /// Uses FontScannerCache to avoid re-scanning the same face multiple times. + /// + private static List ScanTtcFile(string filePath) + { + var faces = new List(); + + using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FontsBinaryReader reader = new FontsBinaryReader(fs)) + { + try + { + uint tag = reader.ReadUInt32BigEndian(); + if (tag != 0x74746366) // "ttcf" + { + return faces; // Not a TTC file – return empty list + } + + uint ttcVersion = reader.ReadUInt32BigEndian(); + uint numFonts = reader.ReadUInt32BigEndian(); + + // Sanity check – prevent huge or corrupt TTC from causing issues + if (numFonts == 0 || numFonts > 1024) + { + return faces; + } + + var offsets = new uint[numFonts]; + for (int i = 0; i < numFonts; i++) + { + offsets[i] = reader.ReadUInt32BigEndian(); + } + + foreach (uint offset in offsets) + { + // Skip obviously invalid offsets + if (offset >= fs.Length) + { + continue; + } + + try + { + var face = FontScannerCache.GetOrAdd(filePath, (long)offset, (path, off) => + { + var f = FontScannerV2Core.ScanSingleFace(path, off); + // Explicitly mark as TTC – regardless of what ScanSingleFace detected + f.Format = FontFormat.Ttc; + return f; + }); + + faces.Add(face); + } + catch (Exception ex) when ( + ex is EndOfStreamException || + ex is IOException || + ex is InvalidOperationException || + ex is ArgumentException) + { + // These indicate a corrupt or malformed font face inside the TTC + System.Diagnostics.Debug.WriteLine( + $"[FontScannerV2] Failed to scan TTC face at offset 0x{offset:X8} in {filePath}\r\n" + + $" Exception: {ex.GetType().Name}: {ex.Message}"); + } + catch (Exception ex) + { + // Unexpected error – log fully + System.Diagnostics.Debug.WriteLine( + $"[FontScannerV2] UNEXPECTED ERROR scanning TTC face at offset 0x{offset:X8} in {filePath}\r\n" + + $" Exception: {ex.GetType().Name}\r\n" + + $" Message: {ex.Message}\r\n" + + $" Stack: {ex.StackTrace}"); + } + } + } + catch (Exception ex) when (ex is EndOfStreamException || ex is IOException) + { + System.Diagnostics.Debug.WriteLine( + $"[FontScannerV2] Failed to read TTC header in file: {filePath}\r\n" + + $" Exception: {ex.GetType().Name}: {ex.Message}"); + } + } + + + + return faces; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.cs new file mode 100644 index 0000000000..fca2175447 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2.cs @@ -0,0 +1,197 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2026 EPPlus Software AB OpenType font implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontResolver; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + internal static partial class FontScannerV2 + { + public static FontFaceInfo FindBestMatch( + string additionalDirectory, + string familyName, + FontSubFamily desiredStyle, + bool searchSystemDirectories = true) + { + var dirs = new List() { additionalDirectory }; + return FindBestMatch(dirs, familyName, desiredStyle, searchSystemDirectories); + } + + public static FontFaceInfo FindBestMatch( + IEnumerable additionalDirectories, + string familyName, + FontSubFamily desiredStyle, + bool searchSystemDirectories = true) + { + var directories = DefaultFontLocations.GetLocationsCollection(additionalDirectories, searchSystemDirectories); + var candidates = EnumerateAllFaces(directories); + + FontFaceInfo bestMatch = null; + int bestScore = -1; + int nMatches = 0; + foreach (var face in candidates) + { + if (string.IsNullOrEmpty(face.FamilyName)) + continue; + + int score = CalculateMatchScore(face, familyName, desiredStyle); + + + if (score > bestScore) + { + if (score >= 3000) nMatches++; + bestScore = score; + bestMatch = face; + } + } + if (bestMatch == null) + return null; + + // Don't mutate the cached face. The cache returns the same FontFaceInfo instance to all + // callers, and IsExactMatch is per-query state, not a property of the font on disk. + // Mutating the cached instance creates a race condition between parallel callers. + var result = bestMatch.Clone(); + // An exact match requires BOTH the family name and the requested style to match. + // Family-normalized (9_000) + exact style (2_000) = 11_000 is the lowest exact score. + // A face matching only the family but approximating the style (the +500/+1000 branches) + // must not count as exact, or the resolver returns e.g. a Regular face for a Bold request. + result.IsExactMatch = bestScore >= 11_000; + return result; + } + + private static int CalculateMatchScore(FontFaceInfo face, string requestedFamily, FontSubFamily requestedStyle) + { + int score = 0; + + // Normalize: remove whitespace and convert to lowercase for comparison + string faceFamily = face.FamilyName ?? ""; + string faceFamilyNormalized = NormalizeFontName(faceFamily); + string requestedNormalized = NormalizeFontName(requestedFamily); + + // Exact family name (case-insensitive) → decisive win + if (string.Equals(faceFamily, requestedFamily, StringComparison.OrdinalIgnoreCase)) + score += 10_000; + // Exact match after normalization (whitespace removed) + else if (faceFamilyNormalized == requestedNormalized) + score += 9_000; + // One name is substring of the other (e.g. "Aptos Narrow" vs "Aptos") + else if (faceFamilyNormalized.Contains(requestedNormalized) || + requestedNormalized.Contains(faceFamilyNormalized)) + score += 5_000; + // Partial overlap - using IndexOf with StringComparison + else if (faceFamilyNormalized.IndexOf(requestedNormalized, StringComparison.Ordinal) >= 0 || + requestedNormalized.IndexOf(faceFamilyNormalized, StringComparison.Ordinal) >= 0) + score += 1_000; + + bool styleMatches = face.Subfamily == requestedStyle; + + // A variable font is only trustworthy for its default instance. If the requested style is + // not the face's default subfamily, this face cannot deliver it without variation + // interpolation (not yet implemented), so it must not win — disqualify it outright. + // This is what makes a variable "Archivo Narrow Regular" stop masquerading as a Bold match. + if (face.IsVariable && !styleMatches) + return -1; + + // Style matching + if (styleMatches) + score += 2_000; + else if (requestedStyle == FontSubFamily.Regular || face.Subfamily == FontSubFamily.Regular) + score += 500; + else if ((requestedStyle & face.Subfamily) != 0) + score += 1_000; + + return score; + } + + /// + /// Normalizes a font name for fuzzy matching. + /// Removes whitespace, hyphens, and converts to lowercase. + /// + private static string NormalizeFontName(string name) + { + if (string.IsNullOrEmpty(name)) + return string.Empty; + + // Remove common separators + return name.Replace(" ", "") + .Replace("-", "") + .Replace("_", "") + .ToLowerInvariant(); + } + + internal static List EnumerateAllFaces(List directories) + { + var result = new List(); + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (string dir in directories) + { + if (!Directory.Exists(dir)) continue; + + string[] files = FontDirectoryCache.GetFontFiles(dir); + + foreach (string file in files) + { + if (!seen.Add(file)) continue; + + try + { + if (Path.GetExtension(file).Equals(".ttc", StringComparison.OrdinalIgnoreCase)) + { + result.AddRange(ScanTtcFile(file)); + } + else + { + var face = FontScannerCache.GetOrAdd(file, 0, FontScannerV2Core.ScanSingleFace); + result.Add(face); + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[FontScannerV2] Failed to read font: {file} → {ex.GetType().Name}: {ex.Message}"); + } + } + } + + return result; + } + + internal static FontFaceInfo GetFace(string filePath, long offset = 0) + { + return FontScannerCache.GetOrAdd(filePath, offset, FontScannerV2Core.ScanSingleFace); + } + + /// + /// Returns all scanned font faces from a specific directory (and subdirectories). + /// Uses the same high-performance, cached scanning as FindBestMatch. + /// Perfect for diagnostics, font picker UI, or when you need to list all available fonts in a folder. + /// + /// The directory to scan (e.g. @"C:\Windows\Fonts") + /// List of FontFaceInfo for all valid TTF/OTF/TTC faces found + internal static List GetAllScannedFontsInPath(string path) + { + if (string.IsNullOrEmpty(path)) + return new List(); + + if (!Directory.Exists(path)) + return new List(); + + var directories = new List { path }; + return EnumerateAllFaces(directories); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2Core.cs b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2Core.cs new file mode 100644 index 0000000000..f8237e49ee --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/FontScannerV2Core.cs @@ -0,0 +1,144 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2026 EPPlus Software AB OpenType font implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Name; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Core scanning logic – shared between FontScannerV2 and cache. + /// + internal static class FontScannerV2Core + { + /// + /// Scans a single TTF/OTF face at the given offset. + /// Called only by FontScannerCache. + /// + internal static FontFaceInfo ScanSingleFace(string filePath, long offset) + { + var info = new FontFaceInfo + { + FilePath = filePath, + OffsetInFile = offset, + LastWriteTimeUtc = File.GetLastWriteTimeUtc(filePath), + TableRecords = new Dictionary(StringComparer.Ordinal), + Format = FontFormat.Ttf // default fallback + }; + + using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FontsBinaryReader reader = new FontsBinaryReader(fs)) + { + fs.Position = offset; + + uint tag = reader.ReadUInt32BigEndian(); + + // 1. TTC header? + if (tag == 0x74746366) // "ttcf" + { + // This should normally be handled by ScanTtcFile, but we are defensive + info.Format = FontFormat.Ttc; + + // We cannot parse table directory from here – return early with minimal info + // This face will be properly rescanned via ScanTtcFile if needed + return info; + } + + // 2. Regular OpenType/TrueType font + if (tag == 0x00010000) // TrueType (standard sfnt version) + { + info.Format = FontFormat.Ttf; + } + else if (tag == 0x4F54544F) // "OTTO" – OpenType with CFF outlines + { + info.Format = FontFormat.Otf; + } + else + { + // Unknown or corrupt font – throw with clear message + throw new InvalidOperationException( + string.Format("Invalid or unsupported font file signature: 0x{0:X8} in file '{1}' at offset {2}", + tag, filePath, offset)); + } + + // Continue with normal parsing... + ushort numTables = reader.ReadUInt16BigEndian(); + reader.ReadUInt16BigEndian(); // searchRange + reader.ReadUInt16BigEndian(); // entrySelector + reader.ReadUInt16BigEndian(); // rangeShift + + for (int i = 0; i < numTables; i++) + { + long tagPos = fs.Position; + var record = new TableRecord + { + Tag = new Tag(reader), + Checksum = reader.ReadUInt32BigEndian(), + Offset = reader.ReadUInt32BigEndian(), + Length = reader.ReadUInt32BigEndian() + }; + info.TableRecords[record.Tag.Value] = record; + } + + // A font is "variable" if it carries a font variations table. We only need to know that the + // table exists — not parse it — to decide that this face cannot be trusted to deliver a + // non-default subfamily. No extra I/O: the table directory is already in memory. + info.IsVariable = info.TableRecords.ContainsKey("fvar"); + + if (info.TableRecords.TryGetValue("OS/2", out TableRecord os2Rec)) + { + try + { + fs.Position = info.OffsetInFile + os2Rec.Offset + 32; + info.FsSelection = reader.ReadUInt16BigEndian(); + } + catch + { + // Om tabellen är korrupt eller för kort → ignorera, behåll 0 + info.FsSelection = 0; + } + } + else + { + info.FsSelection = 0; + } + + // Read name table for family/subfamily + if (info.TableRecords.TryGetValue("name", out TableRecord nameRec)) + { + fs.Position = nameRec.Offset; + byte[] nameBytes = reader.ReadBytes((int)nameRec.Length); + + var nameTable = new NameTable(); + nameTable.Os2FsSelection = info.FsSelection; + nameTable.LoadFromBytes(nameBytes); + + info.FamilyName = nameTable.GetFamilyName() ?? "Unknown Family"; + info.SubfamilyName = nameTable.GetSubfamilyName() ?? "Regular"; + info.Subfamily = nameTable.GetSubfamilyEnum(); + info.FullFontName = nameTable.GetFullFontName() ?? "Unknown Family Regular"; + } + else + { + info.FamilyName = "Unknown Family"; + info.SubfamilyName = "Regular"; + info.Subfamily = FontSubFamily.Regular; + } + } + + return info; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Scanner/IFontFileReader.cs b/src/EPPlus.Fonts.OpenType/Scanner/IFontFileReader.cs new file mode 100644 index 0000000000..2440e72a84 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/IFontFileReader.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/06/2026 EPPlus Software AB Initial implementation + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Scanner +{ + /// + /// Reads the raw font bytes for a given font face on disk. + /// For TTF/OTF files this is just the file contents. For TTC collection files the + /// individual font is extracted and returned as standalone TTF bytes. + /// + /// + /// This is a seam that lets DefaultFontResolver and other consumers be tested without + /// touching the file system. + /// + internal interface IFontFileReader + { + /// + /// Reads the bytes for the given font face. For TTC files (OffsetInFile > 0) the + /// returned bytes are a standalone TTF representation of the single font at that offset, + /// not the raw TTC file contents. + /// + byte[] ReadFontBytes(FontFaceInfo face); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Scanner/IFontScanner.cs b/src/EPPlus.Fonts.OpenType/Scanner/IFontScanner.cs new file mode 100644 index 0000000000..5e87c8fb2d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Scanner/IFontScanner.cs @@ -0,0 +1,24 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2026 EPPlus Software AB OpenType font implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Scanner; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +internal interface IFontScanner +{ + FontFaceInfo FindBestMatch( + IEnumerable additionalDirectories, + string familyName, + FontSubFamily desiredStyle, + bool searchSystemDirectories); +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/StringBuilderExtensions.cs b/src/EPPlus.Fonts.OpenType/StringBuilderExtensions.cs new file mode 100644 index 0000000000..d7906e5d83 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/StringBuilderExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType +{ + internal static class StringBuilderExtensions + { + /// + /// If the last char in the stringbuilder is a space + /// trim it by adjusting length + /// + /// + public static void TrimEndSpace(this StringBuilder sb) + { + if (sb.Length > 0 && sb[sb.Length - 1] == ' ') + { + sb.Length--; + } + } + /// + /// If there is anything in the stringbuilder append space + /// + /// + public static void AppendSpace(this StringBuilder sb) + { + if (sb.Length > 0) + { + sb.Append(' '); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/CmapSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/CmapSubsetProcessor.cs new file mode 100644 index 0000000000..8296d95b82 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/CmapSubsetProcessor.cs @@ -0,0 +1,193 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class CmapSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // --- PHASE 1: DISCOVERY --- + // In this phase, we only find the original Glyph IDs for the requested characters. + // These will be added to context.IncludedGlyphs so that GlyfAndLocaProcessor + // knows which glyph data to copy. + foreach (uint codePoint in context.UsedCodePoints) + { + ushort oldGid; + if (context.OriginalFont.CmapTable.TryGetGlyphId(codePoint, out oldGid)) + { + if (!context.IncludedGlyphs.Contains(oldGid)) + { + context.IncludedGlyphs.Add(oldGid); + } + } + } + + // Ensure GID 0 (.notdef) is always included + if (!context.IncludedGlyphs.Contains(0)) + { + context.IncludedGlyphs.Add(0); + } + } + + public void Rewrite(FontSubsettingContext context) + { + // Build mapping: Unicode code point → NEW glyph ID in subset + Dictionary cmapMapping = new Dictionary(); + + foreach (uint codePoint in context.UsedCodePoints) + { + ushort oldGid; + if (context.OriginalFont.CmapTable.TryGetGlyphId(codePoint, out oldGid)) + { + ushort newGid; + if (context.OldToNewGlyphId.TryGetValue(oldGid, out newGid)) + { + cmapMapping[codePoint] = newGid; + } + else + { + cmapMapping[codePoint] = 0; // .notdef fallback + } + } + } + + // Always map code point 0 to .notdef (required by spec) + cmapMapping[0] = 0; + + // Check if we need Format 12 (for code points > 0xFFFF like emoji) + bool needsFormat12 = cmapMapping.Keys.Any(cp => cp > 0xFFFF); + + // Build new cmap table + CmapTable newCmap = new CmapTable(); + newCmap.Version = 0; + + if (needsFormat12) + { + // Create Format 12 subtable for full Unicode support + var format12 = CreateFormat12Subtable(cmapMapping); + + // Also create Format 4 for BMP characters (backwards compatibility) + var bmpMapping = cmapMapping.Where(kvp => kvp.Key <= 0xFFFF) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + var format4 = CmapFormat4.CreateFromMappings(bmpMapping); + + // Add Format 12 record (3,10) – Windows Unicode UCS-4 (full range) + EncodingRecord format12Record = new EncodingRecord(Platforms.Windows, 10, 0); + format12Record.Subtable = format12; + newCmap.EncodingRecords.Add(format12Record); + newCmap.SubTables.Add(format12); + + // Add Format 4 record (3,1) – Windows Unicode BMP (backwards compatibility) + EncodingRecord format4Record = new EncodingRecord(Platforms.Windows, 1, 0); + format4Record.Subtable = format4; + newCmap.EncodingRecords.Add(format4Record); + newCmap.SubTables.Add(format4); + + newCmap.NumTables = 2; + } + else + { + // Only BMP characters - Format 4 is sufficient + CmapSubtable4 format4 = CmapFormat4.CreateFromMappings(cmapMapping); + + // (3,1) – Windows Unicode BMP + EncodingRecord winRecord = new EncodingRecord(Platforms.Windows, 1, 0); + winRecord.Subtable = format4; + + // (0,3) – Unicode BMP + EncodingRecord unicodeRecord = new EncodingRecord(Platforms.Unicode, 3, 0); + unicodeRecord.Subtable = format4; + + newCmap.EncodingRecords.Add(winRecord); + newCmap.EncodingRecords.Add(unicodeRecord); + newCmap.SubTables.Add(format4); + newCmap.NumTables = 2; + } + + context.SubsetFont.AddOrReplaceTable(newCmap); + } + + private CmapSubtable12 CreateFormat12Subtable(Dictionary mapping) + { + var subtable = new CmapSubtable12(); + + // Sort by code point + var sortedMappings = mapping.OrderBy(kvp => kvp.Key).ToList(); + + if (sortedMappings.Count == 0) + { + subtable.NumGroups = 0; + subtable.Length = 16; // Header only + return subtable; + } + + // Build sequential groups + uint currentStart = sortedMappings[0].Key; + uint currentStartGid = sortedMappings[0].Value; + uint currentEnd = currentStart; + + for (int i = 1; i < sortedMappings.Count; i++) + { + uint codePoint = sortedMappings[i].Key; + ushort glyphId = sortedMappings[i].Value; + + // Check if this continues the current sequential group + bool isSequential = (codePoint == currentEnd + 1) && + (glyphId == currentStartGid + (codePoint - currentStart)); + + if (isSequential) + { + // Extend current group + currentEnd = codePoint; + } + else + { + // Save current group and start new one + subtable.Groups.Add(new SequencialMapGroup + { + StartCharCode = currentStart, + EndCharCode = currentEnd, + StartGlyphId = currentStartGid + }); + + currentStart = codePoint; + currentStartGid = glyphId; + currentEnd = codePoint; + } + } + + // Add final group + subtable.Groups.Add(new SequencialMapGroup + { + StartCharCode = currentStart, + EndCharCode = currentEnd, + StartGlyphId = currentStartGid + }); + + // Update metadata + subtable.NumGroups = (uint)subtable.Groups.Count; + + // Calculate length: header (16 bytes) + groups (12 bytes each) + subtable.Length = 16 + (subtable.NumGroups * 12); + + return subtable; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/FontSubsettingContext.cs b/src/EPPlus.Fonts.OpenType/Subsetting/FontSubsettingContext.cs new file mode 100644 index 0000000000..3a1f9b5715 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/FontSubsettingContext.cs @@ -0,0 +1,72 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Shared context object passed through the subsetting pipeline. + /// Holds all mutable state needed by processors. + /// .NET 3.5 compatible. + /// + public class FontSubsettingContext + { + // Immutable – set once in constructor + public OpenTypeFont OriginalFont { get; private set; } + public OpenTypeFont SubsetFont { get; private set; } + + // Mutable collections – processors fill these + public HashSet UsedCodePoints { get; private set; } + public HashSet IncludedGlyphs { get; private set; } + public Dictionary OldToNewGlyphId { get; private set; } + public List NewToOldGlyphId { get; private set; } + + internal GsubSubsetProcessor GsubProcessor { get; set; } + + public Dictionary GlyphIdMap { get; } = new Dictionary(); + internal GposSubsetProcessor GposProcessor { get; set; } + + /// + /// Creates a new subsetting context and initializes all collections. + /// + public FontSubsettingContext(OpenTypeFont originalFont, IEnumerable unicodeChars) + { + if (originalFont == null) throw new ArgumentNullException("originalFont"); + + OriginalFont = originalFont; + SubsetFont = new OpenTypeFont(originalFont.Format, true); + + SubsetFont.AddOrReplaceTable(originalFont.HeadTable.Clone()); + if (originalFont.NameTable != null) + SubsetFont.AddOrReplaceTable(originalFont.NameTable.Clone()); + + + UsedCodePoints = new HashSet(); + IncludedGlyphs = new HashSet(); + OldToNewGlyphId = new Dictionary(); + NewToOldGlyphId = new List(); + + // Fill UsedCodePoints (including space) + foreach (int c in unicodeChars) + { + uint cp = (uint)c; + if (cp <= 0x10FFFF) + UsedCodePoints.Add(cp); + } + + // Always include space (code point 32) + UsedCodePoints.Add(32); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/GlyphAndLocaSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/GlyphAndLocaSubsetProcessor.cs new file mode 100644 index 0000000000..ed6bae3a58 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/GlyphAndLocaSubsetProcessor.cs @@ -0,0 +1,159 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Loca; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Subsets the glyf and loca tables, builds glyph ID remapping, and resolves composite glyphs. + /// This processor must run early in the pipeline (after code point collection). + /// Fully compatible with .NET 3.5. + /// + internal class GlyfAndLocaSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // 1. Always include .notdef (GID 0) + context.IncludedGlyphs.Add(0); + + // 2. Recursively find and include all components for composite glyphs + // This is critical for fonts like Times New Roman + context.OriginalFont.GlyfTable.ResolveCompositeGlyphs(context.IncludedGlyphs); + } + + public void Rewrite(FontSubsettingContext context) + { + var sortedOldIds = context.NewToOldGlyphId; + List newGlyphs = new List(sortedOldIds.Count); + + // 1. Clone and remap glyphs + foreach (ushort oldId in sortedOldIds) + { + Glyph originalGlyph = context.OriginalFont.GlyfTable.GetGlyph(oldId); + + if (originalGlyph == null || IsEmpty(originalGlyph)) + { + newGlyphs.Add(new Glyph { Header = new GlyphHeader(0, BoundingRectangle.Empty) }); + } + else + { + newGlyphs.Add(CloneGlyphWithRemappedComponents(originalGlyph, context.OldToNewGlyphId)); + } + } + + // 2. Save the new glyf table + context.SubsetFont.AddOrReplaceTable(new GlyfTable(newGlyphs)); + + // 3. Build loca by ACTUALLY measuring serialized glyphs + List offsets = new List { 0 }; + + using (var ms = new MemoryStream()) + using (var writer = new FontsBinaryWriter(ms)) + { + foreach (Glyph g in newGlyphs) + { + long startPos = ms.Position; + g.Serialize(writer); + long endPos = ms.Position; + + int writtenLength = (int)(endPos - startPos); + int padding = (4 - (writtenLength % 4)) % 4; + + for (int p = 0; p < padding; p++) + writer.Write((byte)0); + + offsets.Add((uint)ms.Position); + } + } + + // 4. Update head and create loca + bool useShortOffsets = offsets[offsets.Count - 1] <= 131070; + context.SubsetFont.HeadTable.IndexToLocFormat = useShortOffsets + ? HeadTable.IndexToLocFormats.Offset16 + : HeadTable.IndexToLocFormats.Offset32; + + context.SubsetFont.AddOrReplaceTable(LocaTable.CreateSubset(offsets, context.SubsetFont.HeadTable.IndexToLocFormat)); + } + + private static bool IsEmpty(Glyph g) + { + return g.Header.numberOfContours == 0 && g.CompositeData == null && g.SimpleData == null; + } + + private static Glyph CloneGlyphWithRemappedComponents(Glyph original, Dictionary oldToNewMap) + { + GlyphHeader header = new GlyphHeader(original.Header.numberOfContours, original.Header.Bounds); + + // Handle Simple Glyph + if (original.Header.numberOfContours > 0 && original.SimpleData != null) + { + SimpleGlyph simple = new SimpleGlyph + { + EndPtsOfContours = (ushort[])original.SimpleData.EndPtsOfContours.Clone(), + Instructions = (byte[])original.SimpleData.Instructions.Clone(), + XBytes = (byte[])original.SimpleData.XBytes.Clone(), + YBytes = (byte[])original.SimpleData.YBytes.Clone(), + FlagRuns = new List() + }; + + foreach (FlagRun run in original.SimpleData.FlagRuns) + { + simple.FlagRuns.Add(new FlagRun { Flag = run.Flag, RepeatCount = run.RepeatCount }); + } + + return new Glyph { Header = header, SimpleData = simple }; + } + + // Handle Composite Glyph + if (original.Header.numberOfContours < 0 && original.CompositeData != null) + { + CompositeGlyph composite = new CompositeGlyph + { + Instructions = (byte[])original.CompositeData.Instructions.Clone(), + Components = new List() + }; + + foreach (GlyphComponent comp in original.CompositeData.Components) + { + // Remap the component's GlyphIndex to the new ID + if (!oldToNewMap.TryGetValue(comp.GlyphIndex, out ushort newGid)) + { + newGid = 0; // Fallback to .notdef + } + + composite.Components.Add(new GlyphComponent + { + Flags = comp.Flags, + GlyphIndex = newGid, + Argument1 = comp.Argument1, + Argument2 = comp.Argument2, + Scale = comp.Scale, + XScale = comp.XScale, + YScale = comp.YScale, + Scale01 = comp.Scale01, + Scale10 = comp.Scale10 + }); + } + + return new Glyph { Header = header, CompositeData = composite }; + } + + return new Glyph { Header = header }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/GposSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/GposSubsetProcessor.cs new file mode 100644 index 0000000000..cc50506f5a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/GposSubsetProcessor.cs @@ -0,0 +1,123 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS subset processor + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.Tables.Gpos.Handlers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Processor for subsetting GPOS (Glyph Positioning) table. + /// Implements the two-phase subsetting pattern: Discover → Rewrite. + /// + internal class GposSubsetProcessor : IFontSubsetProcessor + { + private readonly Dictionary _handlers; + + public GposSubsetProcessor() + { + var handlers = new IGposLookupHandler[] + { + new SinglePosHandler(), // Type 1 + new PairPosHandler(), // Type 2 + new MarkToBaseHandler(), // Type 4 + new ExtensionPosHandler() // Type 9 + }; + _handlers = handlers.ToDictionary(h => h.LookupType); + } + + internal void DiscoverLookup(FontSubsettingContext context, LookupTable lookup) + { + if (_handlers.TryGetValue(lookup.LookupType, out var handler)) + { + handler.Discover(context, lookup, this); + } + } + + /// + /// Phase 1: Discover dependencies. + /// For GPOS, there are typically no additional glyphs to discover + /// (unlike GSUB where ligatures require component glyphs). + /// GPOS only positions existing glyphs. + /// + public void Discover(FontSubsettingContext context) + { + context.GposProcessor = this; + var gpos = context.OriginalFont.GposTable; + if (gpos == null) return; + + + // GPOS typically doesn't discover new glyphs + // But we still iterate through lookups in case future handlers need it + foreach (var lookup in gpos.LookupList.Lookups) + { + DiscoverLookup(context, lookup); + } + } + + /// + /// Phase 2: Rewrite the GPOS table with subsetted lookups and remapped glyph IDs. + /// + public void Rewrite(FontSubsettingContext context) + { + context.GposProcessor = this; + var oldGpos = context.OriginalFont.GposTable; + if (oldGpos == null) return; + + // Count Type 4 (MarkToBase) lookups + int markToBaseCount = 0; + foreach (var lookup in oldGpos.LookupList.Lookups) + { + if (lookup.LookupType == 4 || + (lookup.LookupType == 9 && lookup.SubTables.Count > 0 && + lookup.SubTables[0] is MarkToBaseSubTableFormat1)) + { + markToBaseCount++; + } + } + + var newGpos = oldGpos.Rewrite(context); + + if (newGpos != null) + { + context.SubsetFont.AddOrReplaceTable(newGpos); + } + } + + internal IGposLookupHandler GetHandler(ushort lookupType) + { + if (_handlers.TryGetValue(lookupType, out var handler)) + { + return handler; + } + return null; + } + + public LookupTable RewriteLookup(FontSubsettingContext context, LookupTable lookup) + { + // Find the right handler (SinglePos, PairPos, MarkToBase, etc.) + if (_handlers.TryGetValue(lookup.LookupType, out var handler)) + { + // Run the specific Rewrite logic + return handler.Rewrite(context, lookup); + } + + // If we don't have a handler for this type (e.g., Type 3, 5, 6), + // return null so LookupListTable can create an empty placeholder + return null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/GsubSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/GsubSubsetProcessor.cs new file mode 100644 index 0000000000..b2438f4d83 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/GsubSubsetProcessor.cs @@ -0,0 +1,115 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub.Handlers; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class GsubSubsetProcessor : IFontSubsetProcessor + { + private readonly Dictionary _handlers; + + public GsubSubsetProcessor() + { + var handlers = new IGsubLookupHandler[] + { + new SingleSubstHandler(), + new LigatureSubstHandler(), + new ExtensionSubstHandler(), + new ChainingContextualHandler() + }; + _handlers = handlers.ToDictionary(h => h.LookupType); + } + + internal void DiscoverLookup(FontSubsettingContext context, LookupTable lookup) + { + if (_handlers.TryGetValue(lookup.LookupType, out var handler)) + { + handler.Discover(context, lookup, this); + } + } + + public void Discover(FontSubsettingContext context) + { + context.GsubProcessor = this; + var gsub = context.OriginalFont.GsubTable; + if (gsub == null) return; + + // .NET 3.5 compatible sorting + List initialGlyphs = new List(context.IncludedGlyphs); + initialGlyphs.Sort(); + + int previousGlyphCount; + int iteration = 0; + do + { + iteration++; + previousGlyphCount = context.IncludedGlyphs.Count; + + foreach (var lookup in gsub.LookupList.Lookups) + { + int beforeCount = context.IncludedGlyphs.Count; + DiscoverLookup(context, lookup); + int afterCount = context.IncludedGlyphs.Count; + } + + } while (context.IncludedGlyphs.Count > previousGlyphCount); + + // .NET 3.5 compatible sorting + List finalGlyphs = new List(context.IncludedGlyphs); + finalGlyphs.Sort(); + } + + public void Rewrite(FontSubsettingContext context) + { + context.GsubProcessor = this; + var oldGsub = context.OriginalFont.GsubTable; + if (oldGsub == null) return; + + // Här aktiverar vi din nya kedja! + // Istället för att bygga allt manuellt här, låter vi GsubTable sköta det. + var newGsub = oldGsub.Rewrite(context); + + if (newGsub != null) + { + context.SubsetFont.AddOrReplaceTable(newGsub); + } + } + + internal IGsubLookupHandler GetHandler(ushort lookupType) + { + if (_handlers.TryGetValue(lookupType, out var handler)) + { + return handler; + } + return null; + } + + public LookupTable RewriteLookup(FontSubsettingContext context, LookupTable lookup) + { + // Hitta rätt handler (SingleSubst, ChainingContextual, etc.) + if (_handlers.TryGetValue(lookup.LookupType, out var handler)) + { + // Kör den specifika Rewrite-logiken som vi har jobbat på + return handler.Rewrite(context, lookup); + } + + // Om vi inte har en handler för denna typ (t.ex. Type 2 eller 3), + // returnerar vi null så att LookupListTable kan skapa en tom platshållare + return null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/HeadSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/HeadSubsetProcessor.cs new file mode 100644 index 0000000000..45fb74b461 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/HeadSubsetProcessor.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class HeadSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + var original = context.OriginalFont.HeadTable; + if (original == null) return; + + var head = original.Clone(); + // checkSumAdjustment will be recalculated at font save – we leave it for now + context.SubsetFont.AddOrReplaceTable(head); + } + + public void Rewrite(FontSubsettingContext context) + { + // No implementation + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/HheaSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/HheaSubsetProcessor.cs new file mode 100644 index 0000000000..ee18e0ee47 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/HheaSubsetProcessor.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class HheaSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No implementation + } + + public void Rewrite(FontSubsettingContext context) + { + var original = context.OriginalFont.HheaTable; + if (original == null) return; + + var hhea = original.Clone(); + hhea.numberOfHMetrics = (ushort)context.NewToOldGlyphId.Count; + context.SubsetFont.AddOrReplaceTable(hhea); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/HmtxSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/HmtxSubsetProcessor.cs new file mode 100644 index 0000000000..65b6e04a2e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/HmtxSubsetProcessor.cs @@ -0,0 +1,60 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Subsetting.Processors +{ + /// + /// Creates the final hmtx table for the subset font. + /// Uses the glyph ID remapping from GlyfAndLocaSubsetProcessor. + /// Must run after GlyfAndLocaSubsetProcessor. + /// .NET 3.5 compatible. + /// + internal class HmtxSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No implementation + } + + public void Rewrite(FontSubsettingContext context) + { + var originalHmtx = context.OriginalFont.HmtxTable; + if (originalHmtx == null) return; + + int finalGlyphCount = context.NewToOldGlyphId.Count; + + // Create the new metrics storage + var newHMetrics = new List(finalGlyphCount); + + // In our subset, we simplify by making numberOfHMetrics equal to numGlyphs + // This means we only use the hMetrics list, and leftSideBearings will be empty. + for (int i = 0; i < finalGlyphCount; i++) + { + ushort oldGlyphId = context.NewToOldGlyphId[i]; + + newHMetrics.Add(new LongHorMetric + { + advanceWidth = originalHmtx.GetAdvanceWidth(oldGlyphId), + lsb = originalHmtx.GetLeftSideBearing(oldGlyphId) + }); + } + + var newHmtx = new HmtxTable(newHMetrics); + context.SubsetFont.AddOrReplaceTable(newHmtx); + } + } +} + diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/IFontSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/IFontSubsetProcessor.cs new file mode 100644 index 0000000000..5ca6d86c65 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/IFontSubsetProcessor.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting +{ + public interface IFontSubsetProcessor + { + /// + /// Phase 1: Analyzes the original font to discover dependencies (e.g., ligature glyphs). + /// + void Discover(FontSubsettingContext context); + + + /// + /// Phase 2: Creates the new subsetted table based on the discovered dependencies. + /// + public void Rewrite(FontSubsettingContext context); + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/KernSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/KernSubsetProcessor.cs new file mode 100644 index 0000000000..4a1f75e0a2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/KernSubsetProcessor.cs @@ -0,0 +1,99 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Kern; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Subsets the 'kern' table (format 0 only – the only format used in practice). + /// Only keeps kerning pairs where both left and right glyphs exist in the subset. + /// Preserves coverage flags and recalculates searchRange/entrySelector/rangeShift. + /// Must run after GlyfAndLocaSubsetProcessor. + /// .NET 3.5 compatible. + /// + internal class KernSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + var originalFont = context.OriginalFont; + var subsetFont = context.SubsetFont; + + if (originalFont.KernTable == null || originalFont.KernTable.SubTables.Count == 0) + return; // No kerning in source font + + var oldKern = originalFont.KernTable; + var newKern = new KernTable + { + version = oldKern.version, + numberOfFormat0Tables = 0 + }; + + foreach (var originalSubTable in oldKern.SubTables) + { + // Only format 0 is used in real fonts – skip others + if (originalSubTable.coverage.Format != 0 || originalSubTable.Format0Subtable == null) + continue; + + var oldFormat0 = originalSubTable.Format0Subtable; + var newPairs = new List(); + + foreach (var pair in oldFormat0.Pairs) + { + if (context.OldToNewGlyphId.TryGetValue(pair.left, out ushort newLeft) && + context.OldToNewGlyphId.TryGetValue(pair.right, out ushort newRight)) + { + newPairs.Add(new KerningPair(null!) + { + left = newLeft, + right = newRight, + value = pair.value, + Combined = ((uint)newLeft << 16) | newRight + }); + } + } + + if (newPairs.Count == 0) + continue; + + // Sort pairs by Combined value – required for binary search (spec §5) + newPairs.Sort((a, b) => a.Combined.CompareTo(b.Combined)); + + var newSubTable = new KernSubTable + { + version = originalSubTable.version, + coverage = originalSubTable.coverage, // preserve horizontal/vertical flags + Format0Subtable = new KernSubTableFormat0(null!) + { + nPairs = (ushort)newPairs.Count, + Pairs = newPairs.ToArray() + } + }; + + newKern.SubTables.Add(newSubTable); + newKern.numberOfFormat0Tables++; + } + + // Only add kern table if we actually have pairs + if (newKern.SubTables.Count > 0) + { + subsetFont.AddOrReplaceTable(newKern); + } + } + + public void Rewrite(FontSubsettingContext context) + { + // No implementation + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/MaxpSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/MaxpSubsetProcessor.cs new file mode 100644 index 0000000000..58bd5e5c96 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/MaxpSubsetProcessor.cs @@ -0,0 +1,33 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class MaxpSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No implementation + } + + public void Rewrite(FontSubsettingContext context) + { + + var original = context.OriginalFont.MaxpTable; + if (original == null) return; + + var maxp = original.Clone(); + maxp.numGlyphs = (ushort)context.NewToOldGlyphId.Count; + context.SubsetFont.AddOrReplaceTable(maxp); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/NameSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/NameSubsetProcessor.cs new file mode 100644 index 0000000000..7bbbd32657 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/NameSubsetProcessor.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class NameSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + var original = context.OriginalFont.NameTable; + if (original == null) return; + + // Name table can be kept as-is – it's metadata + context.SubsetFont.AddOrReplaceTable(original.Clone()); + } + + public void Rewrite(FontSubsettingContext context) + { + // No implementation + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/Os2SubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/Os2SubsetProcessor.cs new file mode 100644 index 0000000000..e547220021 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/Os2SubsetProcessor.cs @@ -0,0 +1,98 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Os2; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Creates a correct OS/2 table for the subset font. + /// - Recalculates usWinAscent/Descent from actual glyphs + /// - Sets correct usFirstCharIndex / usLastCharIndex (Windows Font Viewer fix) + /// - Keeps all other fields from original (safe and correct) + /// Must run after GlyfAndLocaSubsetProcessor. + /// .NET 3.5 compatible. + /// + internal class Os2SubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // OS/2 discovery is usually not needed as it contains global metrics. + // We just ensure it's marked for inclusion if necessary. + } + + public void Rewrite(FontSubsettingContext context) + { + var originalFont = context.OriginalFont; + if (originalFont.Os2Table == null) return; + + // Clone the original OS/2 table + Os2Table os2 = originalFont.Os2Table.Clone(); + + // 1. Unicode range (must match what Rewrite in CmapSubsetProcessor produces) + if (context.UsedCodePoints.Count > 0) + { + // Only include points within the Basic Multilingual Plane (0-0xFFFF) + var bmpPoints = context.UsedCodePoints.Where(cp => cp <= 0xFFFF).ToList(); + if (bmpPoints.Count > 0) + { + os2.usFirstCharIndex = (ushort)bmpPoints.Min(); + os2.usLastCharIndex = (ushort)bmpPoints.Max(); + } + } + + // 2. Sync Windows Metrics (usWinAscent / usWinDescent) + // We use the metrics from the original font's head table to ensure coverage + if (originalFont.HeadTable != null) + { + ushort headYMax = (ushort)Math.Max((short)0, originalFont.HeadTable.Ymax); + if (os2.usWinAscent < headYMax) + { + os2.usWinAscent = headYMax; + } + + ushort headYMinAbs = (ushort)Math.Abs(originalFont.HeadTable.Ymin); + if (os2.usWinDescent < headYMinAbs) + { + os2.usWinDescent = headYMinAbs; + } + } + + // 3. Update xAvgCharWidth (Optional but good for validation) + // Many validators appreciate if this is recalculated based on the subset + UpdateAverageCharWidth(context, os2); + + context.SubsetFont.AddOrReplaceTable(os2); + } + + private void UpdateAverageCharWidth(FontSubsettingContext context, Os2Table os2) + { + // Simple average of all glyphs included in the subset + if (context.SubsetFont.HmtxTable != null && context.OldToNewGlyphId.Count > 0) + { + long totalWidth = 0; + int count = 0; + foreach (var newGid in context.OldToNewGlyphId.Values) + { + totalWidth += context.SubsetFont.HmtxTable.GetAdvanceWidth(newGid); + count++; + } + if (count > 0) + { + os2.xAvgCharWidth = (short)(totalWidth / count); + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/PostSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/PostSubsetProcessor.cs new file mode 100644 index 0000000000..9a24f64c12 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/PostSubsetProcessor.cs @@ -0,0 +1,58 @@ +using EPPlus.Fonts.OpenType.Tables.Post; +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Creates a minimal, correct 'post' table for the subset font. + /// Uses format 3.0 (no glyph names) – the recommended format for subset fonts. + /// Preserves italicAngle, underlinePosition, underlineThickness and isFixedPitch from the original. + /// .NET 3.5 compatible. + /// + internal class PostSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No implementation + } + + public void Rewrite(FontSubsettingContext context) + { + + var originalPost = context.OriginalFont.PostTable; + if (originalPost == null) return; + + // Create a clean format 3.0 post table (no glyph names) + var post = new PostTable + { + // Format 3.0 in fixed 16.16 representation + version = new Version16Dot16(0x00030000), + + // Preserve typographic metrics + italicAngle = originalPost.italicAngle, + underlinePosition = originalPost.underlinePosition, + underlineThickness = originalPost.underlineThickness, + isFixedPitch = originalPost.isFixedPitch, + + // Fields not used in 3.0 + minMemType42 = 0, + maxMemType42 = 0, + minMemType1 = 0, + maxMemType1 = 0 + }; + + context.SubsetFont.AddOrReplaceTable(post); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/SubsetFontBuilder.cs b/src/EPPlus.Fonts.OpenType/Subsetting/SubsetFontBuilder.cs new file mode 100644 index 0000000000..9cd9806b58 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/SubsetFontBuilder.cs @@ -0,0 +1,93 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting.Processors; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + /// + /// Orchestrates the process of creating a subset of an OpenType font. + /// + internal class SubsetFontBuilder + { + // The order of processors is critical: Discovery must precede Extraction and Rewriting. + private static IEnumerable Processors => new List + { + // PHASE 1: DISCOVERY - Identify all required Glyph IDs (GIDs) + new CmapSubsetProcessor(), // Maps Unicode characters to initial GIDs + new GsubSubsetProcessor(), // Identifies additional GIDs needed for substitutions/ligatures + new GposSubsetProcessor(), // ← Processes glyph positioning (kerning, accents, etc.) + + // PHASE 2: DATA EXTRACTION - Retrieve glyph outlines and metrics + new GlyfAndLocaSubsetProcessor(), + + // PHASE 3: METADATA & TABLES - Update remaining font tables + new MaxpSubsetProcessor(), + new HeadSubsetProcessor(), + new NameSubsetProcessor(), + new HheaSubsetProcessor(), + new HmtxSubsetProcessor(), + new VheaSubsetProcessor(), + new VmtxSubsetProcessor(), + new Os2SubsetProcessor(), + new PostSubsetProcessor(), + new KernSubsetProcessor() + }; + + /// + /// Creates a new containing only the necessary data for the specified characters. + /// + public OpenTypeFont CreateSubset(OpenTypeFont originalFont, IEnumerable unicodeChars) + { + var context = new FontSubsettingContext(originalFont, unicodeChars); + var processors = Processors; + + // Step 1: Discovery Phase - All processors identify required glyphs + foreach (var processor in processors) + { + processor.Discover(context); + } + + // Step 2: Build Glyph ID Mapping + BuildGlyphMapping(context); + + // Step 3: Rewrite Phase - Reconstruct tables using the new Glyph IDs + foreach (var processor in processors) + { + processor.Rewrite(context); + } + + context.SubsetFont.UsedCodePointsForSubset = new List(context.UsedCodePoints); + + context.SubsetFont.SubsetGlyphMapping = new Dictionary(context.OldToNewGlyphId); + + return context.SubsetFont; + } + + // Creates a deterministic mapping between old and new Glyph IDs. + private void BuildGlyphMapping(FontSubsettingContext context) + { + var sortedGlyphs = new List(context.IncludedGlyphs); + sortedGlyphs.Sort(); + + for (ushort newId = 0; newId < sortedGlyphs.Count; newId++) + { + ushort oldId = sortedGlyphs[newId]; + context.OldToNewGlyphId[oldId] = newId; + context.NewToOldGlyphId.Add(oldId); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/SubsetPostProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/SubsetPostProcessor.cs new file mode 100644 index 0000000000..580ff88f88 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/SubsetPostProcessor.cs @@ -0,0 +1,158 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Subsetting +{ + internal class SubsetPostProcessor + { + public void PostProcessSubset(OpenTypeFont font) + { + // 1) Sort table records by tag (spec requires directory sorted alphabetically) + var sortedRecords = font.TableRecords + .OrderBy(r => r.Key) + .Select(r => r.Value) + .ToList(); + + int numTables = sortedRecords.Count; + uint offset = (uint)(12 + numTables * 16); // sfnt header (12) + table directory (16 * numTables) + + // Ensure we have a cache for padded bytes used by serializer + font.PreprocessedPaddedTables?.Clear(); + + // 2) For checksum total, head.checkSumAdjustment must be 0 initially + font.HeadTable.ChecksumAdjustment = 0; + + // 3) Serialize each table, pad to 4 bytes, compute checksum via ChecksumCalculator + foreach (var record in sortedRecords) + { + string tag = record.Tag.Value; + + byte[] rawBytes = font.GetTableData(tag); // unpadded + int rawLen = rawBytes?.Length ?? 0; + + // Pad to 4-byte boundary for checksum and layout + int paddedLen = (rawLen + 3) & ~3; + if (paddedLen > rawLen) + { + Array.Resize(ref rawBytes, paddedLen); // zero-padding + } + + // Compute checksum using the shared calculator (handles head zeroing) + uint checksum = ChecksumCalculator.CalculateTableChecksum(rawBytes, tag); + + // Update TableRecord + record.Offset = offset; + record.Length = (uint)(rawLen); // length must be UNPADDED per spec + record.Checksum = checksum; + + // Cache padded bytes for the serializer to write verbatim + font.PreprocessedPaddedTables[tag] = rawBytes; + + // Advance offset by padded length + offset += (uint)paddedLen; + } + + // 4) Compute the font-wide checksum with head.checkSumAdjustment == 0 + uint totalSum = ComputeFontChecksum(font, sortedRecords, font.PreprocessedPaddedTables); + uint adjustment = 0xB1B0AFBA - totalSum; + + // 5) Update head.checkSumAdjustment, re-serialize head table and recompute its checksum + font.HeadTable.ChecksumAdjustment = adjustment; + + // Re-serialize HEAD (un-padded), then pad for checksum and cache + byte[] headRaw = font.GetTableData("head"); // unpadded AFTER adjustment was set + int headRawLen = headRaw.Length; + int headPaddedLen = (headRawLen + 3) & ~3; + if (headPaddedLen > headRawLen) + { + Array.Resize(ref headRaw, headPaddedLen); + } + + // Recompute head checksum using shared calculator (which zeroes bytes 8–11) + uint headChecksum = ChecksumCalculator.CalculateTableChecksum(headRaw, "head"); + var headRecord = sortedRecords.First(r => r.Tag.Value == "head"); + headRecord.Checksum = headChecksum; + + // Update cache with the final padded HEAD bytes (with adjustment included) + font.PreprocessedPaddedTables["head"] = headRaw; + } + + private uint ComputeFontChecksum(OpenTypeFont font, + List records, + Dictionary paddedTables) + { + // Header + byte[] header = BuildSfntHeader(records.Count); + uint sum = ChecksumCalculator.CalculateTableChecksum(header, ""); // tag unused here + + // Table directory (concatenate directory entries) + foreach (var record in records) + { + byte[] dirEntry = BuildTableRecordBytes(record); // 16 bytes + sum += ChecksumCalculator.CalculateTableChecksum(dirEntry, ""); + } + + // Tables (already padded) + foreach (var kvp in paddedTables) + { + sum += ChecksumCalculator.CalculateTableChecksum(kvp.Value, kvp.Key); + } + + return sum; + } + + private byte[] BuildSfntHeader(int numTables) + { + using var ms = new MemoryStream(); + using var writer = new FontsBinaryWriter(ms); + + writer.WriteUInt32BigEndian(0x00010000); // TrueType sfntVersion + writer.WriteUInt16BigEndian((ushort)numTables); + + int maxPower2 = 1; + int entrySelector = 0; + while (maxPower2 * 2 <= numTables) + { + maxPower2 *= 2; + entrySelector++; + } + ushort searchRange = (ushort)(maxPower2 * 16); + ushort rangeShift = (ushort)(numTables * 16 - searchRange); + + writer.WriteUInt16BigEndian(searchRange); + writer.WriteUInt16BigEndian((ushort)entrySelector); + writer.WriteUInt16BigEndian(rangeShift); + + return ms.ToArray(); + } + + private byte[] BuildTableRecordBytes(TableRecord record) + { + using var ms = new MemoryStream(); + using var writer = new FontsBinaryWriter(ms); + + writer.Write(record.Tag.ToBytes()); // 4 bytes ASCII + writer.WriteUInt32BigEndian(record.Checksum); + writer.WriteUInt32BigEndian(record.Offset); + writer.WriteUInt32BigEndian(record.Length); + + return ms.ToArray(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/VheaSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/VheaSubsetProcessor.cs new file mode 100644 index 0000000000..d58ef4df73 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/VheaSubsetProcessor.cs @@ -0,0 +1,41 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vhea subset processor (vertical text support) + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Subsetting.Processors +{ + /// + /// Creates the subsetted 'vhea' (Vertical Header) table. + /// Only runs if the original font contains a vhea table. + /// Analogous to for the horizontal header. + /// Clones the original vhea and updates NumberOfVMetrics to match + /// the subset glyph count (mirroring how HheaSubsetProcessor updates numberOfHMetrics). + /// + internal class VheaSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No additional glyphs to discover + } + + public void Rewrite(FontSubsettingContext context) + { + var originalVhea = context.OriginalFont.VheaTable; + + // vhea is optional - skip silently if not present + if (originalVhea == null) return; + + var vhea = originalVhea.Clone(); + vhea.NumberOfVMetrics = (ushort)context.NewToOldGlyphId.Count; + context.SubsetFont.AddOrReplaceTable(vhea); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Subsetting/VmtxSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Subsetting/VmtxSubsetProcessor.cs new file mode 100644 index 0000000000..dd9e6104e1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Subsetting/VmtxSubsetProcessor.cs @@ -0,0 +1,59 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vmtx subset processor (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Vmtx; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Subsetting.Processors +{ + /// + /// Creates the subsetted 'vmtx' (Vertical Metrics) table. + /// Only runs if the original font contains a vmtx table. + /// Analogous to for horizontal metrics. + /// Must run after GlyfAndLocaSubsetProcessor so that NewToOldGlyphId is populated. + /// + internal class VmtxSubsetProcessor : IFontSubsetProcessor + { + public void Discover(FontSubsettingContext context) + { + // No additional glyphs to discover - vmtx only carries metrics + } + + public void Rewrite(FontSubsettingContext context) + { + var originalVmtx = context.OriginalFont.VmtxTable; + + // vmtx is optional - skip silently if not present + if (originalVmtx == null) return; + + int finalGlyphCount = context.NewToOldGlyphId.Count; + + // Simplify: set numberOfVMetrics == numGlyphs (same approach as HmtxSubsetProcessor). + // This means all entries go into VMetrics and TopSideBearings stays empty. + var newVMetrics = new List(finalGlyphCount); + + for (int i = 0; i < finalGlyphCount; i++) + { + ushort oldGlyphId = context.NewToOldGlyphId[i]; + + newVMetrics.Add(new LongVerMetric + { + AdvanceHeight = originalVmtx.GetAdvanceHeight(oldGlyphId), + TopSideBearing = originalVmtx.GetTopSideBearing(oldGlyphId) + }); + } + + var newVmtx = new VmtxTable(newVMetrics); + context.SubsetFont.AddOrReplaceTable(newVmtx); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TableRecord.cs b/src/EPPlus.Fonts.OpenType/TableRecord.cs new file mode 100644 index 0000000000..62df6567d0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TableRecord.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType +{ + public class TableRecord + { + public Tag Tag { get; set; } + + public uint Checksum { get; set; } + + public uint Offset { get; set; } + + public uint Length { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable0.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable0.cs new file mode 100644 index 0000000000..d7ab162508 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable0.cs @@ -0,0 +1,70 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapSubtable0 : CmapSubtableBase + { + public CmapSubtable0() + { + GlyphIdArray = new byte[256]; + } + + public override ushort Format { get { return 0; } } + + public override uint Length { get; internal set; } + + public override uint Language { get; internal set; } + + /// + /// Maps character codes 0–255 to glyph indices. + /// + public byte[] GlyphIdArray { get; internal set; } + + + public override GlyphMappings GetGlyphMappings() + { + var mapping = new GlyphMappings(); + + for (uint charCode = 0; charCode < 256; charCode++) + { + ushort glyphIndex = GlyphIdArray[charCode]; + if (glyphIndex != 0) + { + mapping.AddMapping(charCode, glyphIndex); + } + } + + return mapping; + } + + internal override int MapCodePointToGlyph(int codePoint) + { + if (codePoint < 0 || codePoint > 255) + return -1; // Utanför intervallet + + return GlyphIdArray[codePoint]; + } + + + + internal override void Serialize(FontsBinaryWriter writer) + { + var serializer = new CmapSubtable02Serializer(); + serializer.Serialize(this, writer); + + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable12.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable12.cs new file mode 100644 index 0000000000..2a228ea978 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable12.cs @@ -0,0 +1,126 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapSubtable12 : CmapSubtableBase + { + public override ushort Format { get; } = 12; + + public override uint Length { get; internal set; } + + public override uint Language { get; internal set; } + + public ushort Reserved { get; } = 0; + + public uint NumGroups { get; internal set; } + + public List Groups { get; } = new List(); + + public override GlyphMappings GetGlyphMappings() + { + var mapping = new GlyphMappings(); + + foreach (var group in Groups) + { + uint startCharCode = group.StartCharCode; + uint endCharCode = group.EndCharCode; + uint startGlyphId = group.StartGlyphId; + + for (uint charCode = startCharCode; charCode <= endCharCode; charCode++) + { + ushort glyphIndex = (ushort)(startGlyphId + (charCode - startCharCode)); + mapping.AddMapping(charCode, glyphIndex); + } + } + + return mapping; + } + + + internal override int MapCodePointToGlyph(int codePoint) + { + int left = 0; + int right = Groups.Count - 1; + + while (left <= right) + { + int mid = (left + right) / 2; + var group = Groups[mid]; + + if (codePoint < group.StartCharCode) + right = mid - 1; + else if (codePoint > group.EndCharCode) + left = mid + 1; + else + return (int)(group.StartGlyphId + (codePoint - group.StartCharCode)); + } + + return -1; + } + + + public override bool TryGetGlyphId(uint codePoint, out ushort glyphId) + { + glyphId = 0; + + // Performance optimization: Use binary search + // Groups are sorted by StartCharCode per OpenType spec + + if (Groups == null || Groups.Count == 0) + return false; + + int left = 0; + int right = Groups.Count - 1; + + while (left <= right) + { + int mid = left + (right - left) / 2; + var group = Groups[mid]; + + if (codePoint < group.StartCharCode) + { + // Code point is before this group + right = mid - 1; + } + else if (codePoint > group.EndCharCode) + { + // Code point is after this group + left = mid + 1; + } + else + { + // Code point is within this group's range + uint offset = codePoint - group.StartCharCode; + glyphId = (ushort)(group.StartGlyphId + offset); + return glyphId != 0; + } + } + + // Not found in any group + return false; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + var serializer = new CmapSubtable12Serializer(); + serializer.Serialize(this, writer); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable14.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable14.cs new file mode 100644 index 0000000000..7a7967c8f3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable14.cs @@ -0,0 +1,95 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/19/2026 EPPlus Software AB Performance optimization with binary search + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapSubtable14 : CmapSubtableBase + { + public override ushort Format { get; } = 14; + public override uint Length { get; internal set; } + public override uint Language { get; internal set; } + public List VariationSelectors { get; } = new List(); + + public override GlyphMappings GetGlyphMappings() + { + var mapping = new GlyphMappings(); + // Iterate through all variation selectors in the table + foreach (var selector in VariationSelectors) + { + // Only Non-Default UVS tables contain explicit glyph mappings + if (selector.NonDefaultUvsTable != null) + { + foreach (var entry in selector.NonDefaultUvsTable.Mappings) + { + // Add mapping from Unicode value to glyph index + // Note: Variation selector is ignored here, since GlyphMapping is flat + mapping.AddMapping(entry.UnicodeValue, entry.GlyphId); + } + } + // Default UVS tables do not contain glyph indices and are not included + } + return mapping; + } + + internal override int MapCodePointToGlyph(int codePoint) + { + // Performance optimization: Use binary search instead of linear scan + // OpenType spec guarantees that Mappings are sorted by UnicodeValue + + foreach (var selector in VariationSelectors) + { + if (selector.NonDefaultUvsTable != null && selector.NonDefaultUvsTable.Mappings.Count > 0) + { + // Binary search for the codePoint + var mappings = selector.NonDefaultUvsTable.Mappings; + int left = 0; + int right = mappings.Count - 1; + + while (left <= right) + { + int mid = left + (right - left) / 2; + uint unicodeValue = mappings[mid].UnicodeValue; + + if (unicodeValue == codePoint) + { + return mappings[mid].GlyphId; + } + else if (unicodeValue < codePoint) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + } + } + + return -1; // Not found + } + + internal override void Serialize(FontsBinaryWriter writer) + { + var serializer = new CmapSubtable14Serializer(); + serializer.Serialize(this, writer); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4.cs new file mode 100644 index 0000000000..d19ed73526 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4.cs @@ -0,0 +1,168 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/19/2026 EPPlus Software AB Performance optimization with binary search + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class CmapSubtable4 : CmapSubtableBase + { + + public override ushort Format { get; } = 4; + + public override uint Length { get; internal set; } + + public override uint Language { get; internal set; } + + public ushort SegCountX2 { get; internal set; } + public ushort SearchRange { get; internal set; } + public ushort EntrySelector { get; internal set; } + public ushort RangeShift { get; internal set; } + + public ushort[] EndCode { get; internal set; } = new ushort[0]; + public ushort ReservedPad { get; internal set; } + public ushort[] StartCode { get; internal set; } = new ushort[0]; + public short[] IdDelta { get; internal set; } = new short[0]; + public ushort[] IdRangeOffset { get; internal set; } = new ushort[0]; + + public ushort[] GlyphIdArray { get; internal set; } = new ushort[0]; + + public override GlyphMappings GetGlyphMappings() + { + var mapping = new GlyphMappings(); + + int segCount = EndCode.Length; + + for (int i = 0; i < segCount; i++) + { + ushort startCode = StartCode[i]; + ushort endCode = EndCode[i]; + short idDelta = IdDelta[i]; + ushort idRangeOffset = IdRangeOffset[i]; + + for (uint charCode = startCode; charCode <= endCode; charCode++) + { + ushort glyphIndex; + + if (idRangeOffset == 0) + { + glyphIndex = (ushort)((charCode + idDelta) % 65536); + } + else + { + int offsetIndex = (idRangeOffset / 2) + (int)(charCode - startCode) - (segCount - i); + if (offsetIndex >= 0 && offsetIndex < GlyphIdArray.Length) + { + ushort glyphId = GlyphIdArray[offsetIndex]; + if (glyphId != 0) + { + glyphIndex = (ushort)((glyphId + idDelta) % 65536); + } + else + { + glyphIndex = 0; + } + } + else + { + glyphIndex = 0; + } + } + + if (glyphIndex != 0) + { + mapping.AddMapping(charCode, glyphIndex); + } + } + } + + return mapping; + } + + internal override int MapCodePointToGlyph(int codePoint) + { + // Performance optimization: Use binary search to find the segment + // EndCode array is sorted in ascending order per OpenType spec + + if (codePoint < 0 || codePoint > 0xFFFF) + return -1; + + int segCount = EndCode.Length; + if (segCount == 0) + return -1; + + // Binary search for the segment containing this codePoint + // We're looking for the first EndCode >= codePoint + int left = 0; + int right = segCount - 1; + int segmentIndex = -1; + + while (left <= right) + { + int mid = left + (right - left) / 2; + + if (EndCode[mid] >= codePoint) + { + segmentIndex = mid; + right = mid - 1; // Continue searching left for earlier match + } + else + { + left = mid + 1; + } + } + + // If no segment found or codePoint is before the segment's start, return -1 + if (segmentIndex == -1 || codePoint < StartCode[segmentIndex]) + return -1; + + // Found the segment, now map to glyph + int i = segmentIndex; + + if (IdRangeOffset[i] == 0) + { + // Simple offset mapping + return (codePoint + IdDelta[i]) & 0xFFFF; + } + else + { + // Index into GlyphIdArray + int offset = IdRangeOffset[i] / 2 + (codePoint - StartCode[i]) - (segCount - i); + + if (offset >= 0 && offset < GlyphIdArray.Length) + { + ushort glyphId = GlyphIdArray[offset]; + if (glyphId != 0) + { + return (glyphId + IdDelta[i]) & 0xFFFF; + } + } + } + + return -1; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + var serializer = new CmapSubtable4Serializer(); + serializer.Serialize(this, writer); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4Segment.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4Segment.cs new file mode 100644 index 0000000000..e0f6be8274 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable4Segment.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapSubtable4Segment + { + public ushort StartCode { get; set; } + public ushort EndCode { get; set; } + public short IdDelta { get; set; } + public ushort IdRangeOffset { get; set; } // 0 if not used + public ushort[]? GlyphIdArray { get; set; } // Only if IdRangeOffset > 0 + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable6.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable6.cs new file mode 100644 index 0000000000..00feaf8fb2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtable6.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapSubtable6 : CmapSubtableBase + { + public override ushort Format => 6; + + public override uint Length { get; internal set; } + + public override uint Language { get; internal set; } + + public ushort FirstCode { get; internal set; } + + public ushort EntryCount { get; internal set; } + + public ushort[] GlyphIdArray { get; internal set; } = new ushort[0]; + + public override GlyphMappings GetGlyphMappings() + { + var mapping = new GlyphMappings(); + + for (int i = 0; i < EntryCount && i < GlyphIdArray.Length; i++) + { + uint charCode = (uint)(FirstCode + i); + ushort glyphIndex = GlyphIdArray[i]; + + mapping.AddMapping(charCode, glyphIndex); + } + + return mapping; + } + + + internal override int MapCodePointToGlyph(int codePoint) + { + if (codePoint < FirstCode || codePoint >= FirstCode + EntryCount) + return -1; // Not found + + int index = codePoint - FirstCode; + if (index >= 0 && index < GlyphIdArray.Length) + { + return GlyphIdArray[index]; + } + + return -1; // Not found + } + + internal override void Serialize(FontsBinaryWriter writer) + { + var serializer = new CmapSubtable6_2Serializer(); + serializer.Serialize(this, writer); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtableBase.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtableBase.cs new file mode 100644 index 0000000000..ab4b25fec7 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapSubtableBase.cs @@ -0,0 +1,75 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Mappings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public abstract class CmapSubtableBase : FontTableElement + { + /// + /// Format identifier (0, 4, 6, etc.) + /// + public abstract ushort Format { get; } + + /// + /// Length of the subtable in bytes + /// + public abstract uint Length { get; internal set; } + + /// + /// Language code (optional usage depending on format) + /// + public abstract uint Language { get; internal set; } + + /// + /// Returns for the subtable. + /// + /// + public abstract GlyphMappings GetGlyphMappings(); + + internal abstract int MapCodePointToGlyph(int codePoint); + + + /// + /// Attempts to map a Unicode code point to a glyph ID. + /// Returns true if mapping exists, otherwise false. + /// + /// Unicode code point + /// Glyph ID if found + /// True if mapping exists + public virtual bool TryGetGlyphId(uint codePoint, out ushort glyphId) + { + // Säker cast – codePoint > int.MaxValue hanteras inte av format 4/12 i praktiken + if (codePoint > int.MaxValue) + { + glyphId = 0; + return false; + } + + int result = MapCodePointToGlyph((int)codePoint); + if (result >= 0) + { + glyphId = (ushort)result; + return true; + } + + glyphId = 0; + return false; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTable.cs new file mode 100644 index 0000000000..3790758cff --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTable.cs @@ -0,0 +1,278 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + /// + /// This table defines the mapping of character codes to the glyph index values used in the font. It may contain more than one subtable, in order to support more than one character encoding scheme. + /// + public class CmapTable : FontTableBase + { + internal CmapTable() + { + EncodingRecords = new List(); + SubTables = new List(); + } + + public override string Name => TableNames.Cmap; + + public override bool IsEssentialTable => true; + + /// + /// Table version number (0). + /// + public ushort Version { get; set; } + + /// + /// Number of encoding tables that follow. + /// + public ushort NumTables { get; set; } + + /// + /// The array of encoding records specifies particular encodings and the offset to the subtable for each encoding. + /// + public List EncodingRecords { get; private set; } + + /// + /// Array of Subtables + /// + public List SubTables { get; private set; } + + + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + // Start of cmap table + long tableStart = writer.BaseStream.Position; + + // Write header + writer.WriteUInt16BigEndian(Version); + writer.WriteUInt16BigEndian((ushort)EncodingRecords.Count); + + // Reserve space for encoding records + long encodingRecordStart = writer.BaseStream.Position; + foreach (var _ in EncodingRecords) + { + writer.Write(new byte[8]); // placeholder + } + + // Precompute offsets for unique subtables + var subtableOffsetsMap = new Dictionary(); + var subTableStartIndex = writer.BaseStream.Position; + var encRecordsToSerialize = EncodingRecords.OrderBy(er => er.SubtableOffset); + var usedSubtables = new Dictionary(); + foreach(var encRecord in encRecordsToSerialize) + { + // Skip format 14 and any explicitly marked skipped records + if (encRecord.IsSkipped || (encRecord.Subtable?.Format == 14)) + { + continue; + } + if (usedSubtables.ContainsKey(encRecord.SubtableOffset)) + { + encRecord.SubtableOffset = usedSubtables[encRecord.SubtableOffset]; + continue; + } + var subTableBytes = encRecord.Subtable.Serialize(); + writer.Write(subTableBytes); + usedSubtables.Add(encRecord.SubtableOffset, (uint)subTableStartIndex); + encRecord.SubtableOffset = (uint)subTableStartIndex; + subTableStartIndex += subTableBytes.Length; + + } + + // Go back and write encoding records with correct offsets + long currentPos = writer.BaseStream.Position; + writer.BaseStream.Seek(encodingRecordStart, SeekOrigin.Begin); + + for (int i = 0; i < EncodingRecords.Count; i++) + { + var record = EncodingRecords[i]; + writer.WriteUInt16BigEndian((ushort)record.PlatformId); + writer.WriteUInt16BigEndian(record.EncodingId); + writer.WriteUInt32BigEndian(record.SubtableOffset); + } + + // Return to end of stream + writer.BaseStream.Seek(currentPos, SeekOrigin.Begin); + } + + + public int MapCharToGlyph(char ch) + { + int codePoint = ch; // Unicode value + foreach (var subtable in SubTables) + { + int glyphId = subtable.MapCodePointToGlyph(codePoint); + if (glyphId >= 0) + return glyphId; + } + return -1; // Not found + } + + + public int GetMinCharCode() + { + int minCode = int.MaxValue; + + // Defensive: handle empty/none + if (SubTables == null || SubTables.Count == 0) + return 0; + + for (int i = 0; i < SubTables.Count; i++) + { + CmapSubtableBase sub = SubTables[i]; + if (sub == null) continue; + + var mappings = sub.GetGlyphMappings(); + if (mappings == null || mappings.CharCodeToGlyphIndex == null) continue; + + // Iterate all char-code → glyph-index pairs + foreach (KeyValuePair kvp in mappings.CharCodeToGlyphIndex) + { + // glyphIndex is ushort, so it's always >= 0; we only need the char code + uint code = kvp.Key; + if (code < (uint)minCode) + { + minCode = (int)code; + } + } + } + + // If no mappings found, return 0 + return (minCode == int.MaxValue) ? 0 : minCode; + } + + public int GetMaxCharCode() + { + int maxCode = int.MinValue; + + if (SubTables == null || SubTables.Count == 0) + return 0; + + for (int i = 0; i < SubTables.Count; i++) + { + CmapSubtableBase sub = SubTables[i]; + if (sub == null) continue; + + var mappings = sub.GetGlyphMappings(); + if (mappings == null || mappings.CharCodeToGlyphIndex == null) continue; + + foreach (KeyValuePair kvp in mappings.CharCodeToGlyphIndex) + { + uint code = kvp.Key; + if (code > (uint)maxCode) + { + maxCode = (int)code; + } + } + } + + return (maxCode == int.MinValue) ? 0 : maxCode; + } + + + public bool ContainsChar(ushort charCode) + { + foreach (var subtable in SubTables) + { + if (subtable.TryGetGlyphId(charCode, out _)) + { + return true; + } + } + return false; + } + + + public bool TryGetGlyphId(uint codePoint, out ushort glyphId) + { + glyphId = 0; + + var preferred = GetPreferredSubtable(); + if (preferred != null && preferred.TryGetGlyphId(codePoint, out glyphId) && glyphId != 0) + { + return true; + } + + // Fallback: loopa alla + foreach (var subtable in SubTables) + { + if (subtable.TryGetGlyphId(codePoint, out glyphId) && glyphId != 0) + return true; + } + + return false; + } + + + + public CmapSubtableBase GetPreferredSubtable() + { + + // Prioritetsordning: Format 12 > Format 4 > Format 6 > Format 0 + var preferredFormats = new ushort[] { 12, 4, 6, 0 }; + + foreach (var format in preferredFormats) + { + for (int i = 0; i < EncodingRecords.Count; i++) + { + var record = EncodingRecords[i]; + if (record.PlatformId == Platforms.Windows && record.EncodingId == 1) + { + var subtable = EncodingRecords[i].Subtable; + if (subtable != null && subtable.Format == format) + { + return subtable; + } + } + } + } + + return null; + + } + + internal override void Clear() + { + NumTables = 0; + EncodingRecords.Clear(); + SubTables.Clear(); + } + + public uint GetUnicodeCodePoint(ushort glyphId) + { + foreach (var subtable in SubTables) + { + var mappings = subtable.GetGlyphMappings(); + if (mappings == null) continue; + + foreach (var kvp in mappings.CharCodeToGlyphIndex) + { + if (kvp.Value == glyphId) return kvp.Key; + } + } + return 0; + } + + public ushort GetGlyphId(char ch) + { + TryGetGlyphId(ch, out ushort gid); + return gid; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableLoader.cs new file mode 100644 index 0000000000..471d2288b3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableLoader.cs @@ -0,0 +1,122 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap.Serialization; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapTableLoader : TableLoader + { + public CmapTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Cmap) + { + } + + protected override CmapTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + + var table = new CmapTable + { + Version = _reader.ReadUInt16BigEndian(), + NumTables = _reader.ReadUInt16BigEndian() + }; + + // Read encoding records + for (var x = 0; x < table.NumTables; x++) + { + var enc = new EncodingRecord(_reader); + table.EncodingRecords.Add(enc); + } + + // Deduplicate subtables by offset + var subtableCache = new Dictionary(); + + // Process subtables + for (var x = 0; x < table.NumTables; x++) + { + var enc = table.EncodingRecords[x]; + var currentPos = _offset + enc.SubtableOffset; + + if (subtableCache.TryGetValue(enc.SubtableOffset, out var existingSubtable)) + { + // Reuse existing subtable + enc.Subtable = existingSubtable; + continue; + } + + // Read format to determine deserializer + long savedPos = _reader.BaseStream.Position; + _reader.BaseStream.Position = currentPos; + var format = _reader.ReadUInt16BigEndian(); + _reader.BaseStream.Position = savedPos; + + // Deserialize based on format + switch (format) + { + case 0: + var sub0 = new CmapSubtable0Deserializer(_reader).Deserialize(currentPos); + table.SubTables.Add(sub0); + subtableCache[enc.SubtableOffset] = sub0; + enc.Subtable = sub0; + break; + + case 4: + var sub4 = new CmapSubtable4Deserializer(_reader).Deserialize(currentPos); + table.SubTables.Add(sub4); + subtableCache[enc.SubtableOffset] = sub4; + enc.Subtable = sub4; + break; + + case 6: + var sub6 = new CmapSubtable6Deserializer(_reader).Deserialize(currentPos); + table.SubTables.Add(sub6); + subtableCache[enc.SubtableOffset] = sub6; + enc.Subtable = sub6; + break; + + case 12: + var sub12 = new CmapSubtable12Deserializer(_reader).Deserialize(currentPos); + table.SubTables.Add(sub12); + subtableCache[enc.SubtableOffset] = sub12; + enc.Subtable = sub12; + break; + + case 14: + // Skip format 14 (Unicode Variation Sequences) + var dummySubtable = new CmapSubtable14(); + enc.IsSkipped = true; + enc.Subtable = dummySubtable; + subtableCache[enc.SubtableOffset] = dummySubtable; + + _reader.BaseStream.Position = currentPos + 6; + uint length = _reader.ReadUInt32BigEndian(); + long nextTablePos = currentPos + length; + if (nextTablePos > _reader.BaseStream.Length || nextTablePos < currentPos) + { + nextTablePos = _reader.BaseStream.Length; + } + _reader.BaseStream.Position = nextTablePos; + break; + + default: + // Unsupported format - skip + break; + } + } + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableValidator.cs new file mode 100644 index 0000000000..6d624b8401 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/CmapTableValidator.cs @@ -0,0 +1,392 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + internal class CmapTableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Cmap; } + } + + public override Type TableType => typeof(CmapTable); + + public override TableValidationResult Validate(CmapTable cmap, FontValidationContext context) + { + + var result = new TableValidationResult(); + result.TableName = TableName; + + // 1. Kontrollera version + if (cmap.Version != 0) + { + result.AddMessage(FontValidationSeverity.Error, "cmap version must be 0, found " + cmap.Version); + } + + // 2. Kontrollera antal subtables + + if (cmap.NumTables != cmap.SubTables.Count) + { + result.AddMessage(FontValidationSeverity.Information, + $"NumTables ({cmap.NumTables}) does not match unique subtable count ({cmap.SubTables.Count}). This is normal if multiple encoding records share the same subtable."); + } + + + + // 3. Validera varje subtable + foreach (var subtable in cmap.SubTables) + { + ValidateSubtable(subtable, result, context); + } + + + return result; + } + + + private void ValidateSubtable(CmapSubtableBase subtable, TableValidationResult result, FontValidationContext context) + { + switch (subtable.Format) + { + case 0: + ValidateFormat0((CmapSubtable0)subtable, result, context); + break; + case 4: + ValidateFormat4((CmapSubtable4)subtable, result, context); + break; + case 6: + ValidateFormat6((CmapSubtable6)subtable, result, context); + break; + case 12: + ValidateFormat12((CmapSubtable12)subtable, result, context); + break; + case 14: + ValidateFormat14((CmapSubtable14)subtable, result, context); + break; + default: + result.AddMessage(FontValidationSeverity.Warning, + $"Unsupported cmap subtable format: {subtable.Format}"); + break; + } + } + + + private void ValidateFormat0(CmapSubtable0 st, TableValidationResult result, FontValidationContext context) + { + + // 1. Check that GlyphIdArray has correct length + if (st.GlyphIdArray.Length != 256) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 0: GlyphIdArray must have length 256, found {st.GlyphIdArray.Length}."); + } + + // 2. Check that Length matches specification (header + 256 bytes) + if (st.Length != 262) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 0: Length should be 262, found {st.Length}."); + } + + // 3. Validate glyph IDs against maxp.numGlyphs + var maxGlyphs = context.Font.MaxpTable.numGlyphs; + for (int i = 0; i < st.GlyphIdArray.Length; i++) + { + byte glyphId = st.GlyphIdArray[i]; + if (glyphId >= maxGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 0: GlyphIdArray[{i}] = {glyphId} exceeds max glyph count ({maxGlyphs})."); + } + } + + // 4. Optional: Check language field for unusual values + if (st.Language > 0xFFFF) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 0: Language value {st.Language} seems invalid (greater than 0xFFFF)."); + } + + } + + + private void ValidateFormat4(CmapSubtable4 st, TableValidationResult result, FontValidationContext context) + { + int segCount = st.EndCode.Length; + + // 1. Check SegCountX2 consistency + if (st.SegCountX2 != segCount * 2) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: SegCountX2 mismatch. Expected {segCount * 2}, found {st.SegCountX2}."); + } + + // 2. Check that all segment arrays have equal length + if (st.StartCode.Length != segCount || st.IdDelta.Length != segCount || st.IdRangeOffset.Length != segCount) + { + result.AddMessage(FontValidationSeverity.Error, + "Format 4: Segment arrays must have equal length."); + } + + // 3. Check that the last EndCode is 0xFFFF + if (segCount == 0 || st.EndCode[segCount - 1] != 0xFFFF) + { + result.AddMessage(FontValidationSeverity.Error, + "Format 4: Last EndCode must be 0xFFFF."); + } + + // 4. ReservedPad should be zero + if (st.ReservedPad != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "Format 4: ReservedPad should be 0."); + } + + // 5. Validate segment ordering and ranges + for (int i = 0; i < segCount; i++) + { + if (st.StartCode[i] > st.EndCode[i]) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: StartCode[{i}] ({st.StartCode[i]}) > EndCode[{i}] ({st.EndCode[i]})."); + } + + if (i > 0 && st.StartCode[i] <= st.EndCode[i - 1]) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 4: Segment {i} overlaps previous segment."); + } + } + + // 6. Validate glyph IDs in GlyphIdArray against maxp.numGlyphs + var maxGlyphs = context.Font.MaxpTable.numGlyphs; + for (int i = 0; i < st.GlyphIdArray.Length; i++) + { + ushort glyphId = st.GlyphIdArray[i]; + if (glyphId >= maxGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: GlyphIdArray[{i}] = {glyphId} exceeds max glyph count ({maxGlyphs})."); + } + } + + // 7. Optional: Validate IdRangeOffset values + for (int i = 0; i < segCount; i++) + { + ushort offset = st.IdRangeOffset[i]; + if (offset != 0) + { + int calculatedIndex = (offset / 2) + (int)(st.StartCode[i] - st.StartCode[i]) - (segCount - i); + if (calculatedIndex < 0 || calculatedIndex >= st.GlyphIdArray.Length) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 4: IdRangeOffset[{i}] points outside GlyphIdArray."); + } + } + } + + + // 8. Validate searchRange, entrySelector, rangeShift + int maxPower = (int)Math.Pow(2, (int)Math.Floor(Math.Log(segCount, 2))); + ushort expectedSearchRange = (ushort)(maxPower * 2); + ushort expectedEntrySelector = (ushort)Math.Floor(Math.Log(segCount, 2)); + ushort expectedRangeShift = (ushort)((segCount * 2) - expectedSearchRange); + + if (st.SearchRange != expectedSearchRange) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: searchRange mismatch. Expected {expectedSearchRange}, found {st.SearchRange}."); + } + if (st.EntrySelector != expectedEntrySelector) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: entrySelector mismatch. Expected {expectedEntrySelector}, found {st.EntrySelector}."); + } + if (st.RangeShift != expectedRangeShift) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 4: rangeShift mismatch. Expected {expectedRangeShift}, found {st.RangeShift}."); + } + + } + + + + + private void ValidateFormat6(CmapSubtable6 st, TableValidationResult result, FontValidationContext context) + { + // 1. Check that GlyphIdArray length matches EntryCount + if (st.GlyphIdArray.Length != st.EntryCount) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 6: GlyphIdArray length ({st.GlyphIdArray.Length}) does not match EntryCount ({st.EntryCount})."); + } + + // 2. Check that Length matches specification: header (10 bytes) + glyph array (EntryCount * 2) + uint expectedLength = 10 + (uint)st.EntryCount * 2; + if (st.Length != expectedLength) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 6: Length should be {expectedLength}, found {st.Length}."); + } + + // 3. Check that the character range does not exceed 0xFFFF + uint lastCode = (uint)st.FirstCode + (uint)st.EntryCount - 1; + if (lastCode > 0xFFFF) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 6: Character range exceeds 0xFFFF. FirstCode={st.FirstCode}, EntryCount={st.EntryCount}."); + } + + // 4. Validate that all glyph IDs are within the font's glyph count + var maxGlyphs = context.Font.MaxpTable.numGlyphs; + for (int i = 0; i < st.GlyphIdArray.Length; i++) + { + ushort glyphId = st.GlyphIdArray[i]; + if (glyphId >= maxGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 6: GlyphIdArray[{i}] = {glyphId} exceeds max glyph count ({maxGlyphs})."); + } + } + } + + + + private void ValidateFormat12(CmapSubtable12 st, TableValidationResult result, FontValidationContext context) + { + // 1. Check that NumGroups matches actual group count + if (st.Groups.Count != st.NumGroups) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 12: NumGroups ({st.NumGroups}) does not match actual group count ({st.Groups.Count})."); + } + + // 2. Validate each group for logical consistency + for (int i = 0; i < st.Groups.Count; i++) + { + var g = st.Groups[i]; + + // StartCharCode must not be greater than EndCharCode + if (g.StartCharCode > g.EndCharCode) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 12: Group {i} StartCharCode ({g.StartCharCode}) > EndCharCode ({g.EndCharCode})."); + } + + // Groups must not overlap previous group + if (i > 0 && g.StartCharCode <= st.Groups[i - 1].EndCharCode) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 12: Group {i} overlaps previous group. StartCharCode={g.StartCharCode}, PreviousEnd={st.Groups[i - 1].EndCharCode}."); + } + + // Validate glyph range against maxp.numGlyphs + var maxGlyphs = context.Font.MaxpTable.numGlyphs; + ulong glyphRangeEnd = (ulong)g.StartGlyphId + (ulong)(g.EndCharCode - g.StartCharCode); + if (glyphRangeEnd >= (ulong)maxGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 12: Group {i} glyph range exceeds max glyph count ({maxGlyphs}). StartGlyphId={g.StartGlyphId}, EndGlyphId={glyphRangeEnd}."); + } + + // Optional: Validate that character codes do not exceed Unicode max (0x10FFFF) + if (g.EndCharCode > 0x10FFFF) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 12: Group {i} EndCharCode ({g.EndCharCode}) exceeds Unicode maximum (0x10FFFF)."); + } + } + } + + + + + + private void ValidateFormat14(CmapSubtable14 st, TableValidationResult result, FontValidationContext context) + { + // 1. Check that VariationSelectors are sorted + for (int i = 1; i < st.VariationSelectors.Count; i++) + { + if (st.VariationSelectors[i].VarSelector < st.VariationSelectors[i - 1].VarSelector) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 14: VariationSelectors not sorted at index {i}. VarSelector={st.VariationSelectors[i].VarSelector:X6}, previous={st.VariationSelectors[i - 1].VarSelector:X6}."); + } + } + + foreach (var selector in st.VariationSelectors) + { + uint vs = selector.VarSelector; + + // 2. Validate VarSelector range + bool isValidRange = (vs >= 0xFE00 && vs <= 0xFE0F) || (vs >= 0xE0100 && vs <= 0xE01EF); + if (!isValidRange) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 14: VarSelector {vs:X6} is outside standard Unicode variation selector ranges."); + } + + // 3. Validate NonDefault UVS mappings + if (selector.NonDefaultUvsTable != null) + { + var seenUnicodeValues = new HashSet(); + foreach (var entry in selector.NonDefaultUvsTable.Mappings) + { + if (!seenUnicodeValues.Add(entry.UnicodeValue)) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 14: Duplicate UnicodeValue {entry.UnicodeValue:X6} in NonDefault UVS table for VarSelector {vs:X6}."); + } + + var maxGlyphs = context.Font.MaxpTable.numGlyphs; + if (entry.GlyphId >= maxGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Format 14: GlyphId {entry.GlyphId} exceeds max glyph count ({maxGlyphs}) for UnicodeValue {entry.UnicodeValue:X6}."); + } + } + } + + // 4. Validate Default UVS ranges + if (selector.DefaultUvsTable != null) + { + foreach (var range in selector.DefaultUvsTable.Ranges) + { + uint start = range.StartUnicodeValue; + uint end = start + range.AdditionalCount; + + // Check start and end against Unicode max + if (start > 0x10FFFF) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 14: Default UVS range start {start:X6} exceeds Unicode maximum (0x10FFFF)."); + } + if (end > 0x10FFFF) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Format 14: Default UVS range end {end:X6} exceeds Unicode maximum (0x10FFFF)."); + } + + // Optional: Check that ranges are sorted and non-overlapping + // (We can implement this if needed for stricter validation) + } + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/DefaultUvsTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/DefaultUvsTable.cs new file mode 100644 index 0000000000..ccdb1e373b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/DefaultUvsTable.cs @@ -0,0 +1,33 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class DefaultUvsTable : FontTableElement + { + public uint NumUnicodeValueRanges { get; internal set; } + + public List Ranges { get; internal set; } = new List(); + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt32BigEndian((uint)Ranges.Count); + + foreach (var range in Ranges) + { + range.Serialize(writer); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/EncodingRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/EncodingRecord.cs new file mode 100644 index 0000000000..2ffa4c681b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/EncodingRecord.cs @@ -0,0 +1,59 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class EncodingRecord : FontTableElement + { + + internal EncodingRecord(Platforms platformId, ushort encodingId, uint subtableOffset) + { + PlatformId = platformId; + EncodingId = encodingId; + SubtableOffset = subtableOffset; + } + + + internal EncodingRecord(FontsBinaryReader reader) + { + PlatformId = (Platforms)reader.ReadUInt16BigEndian(); + EncodingId = reader.ReadUInt16BigEndian(); + SubtableOffset = reader.ReadUInt32BigEndian(); + } + + /// + /// 0 - Unicode + /// 1 - Macintosh + /// 2 - ISO (deprecated) + /// 3 - Windows + /// 4 - Custom + /// + public Platforms PlatformId { get; private set; } + + + public ushort EncodingId { get; private set; } + + public uint SubtableOffset { get; set; } + + public bool IsSkipped { get; set; } + + public CmapSubtableBase Subtable { get; internal set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian((ushort)PlatformId); + writer.WriteUInt16BigEndian(EncodingId); + writer.WriteUInt32BigEndian(SubtableOffset); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/GlyphMapping.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/GlyphMapping.cs new file mode 100644 index 0000000000..95b499aa78 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/GlyphMapping.cs @@ -0,0 +1,41 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Diagnostics; + + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + [DebuggerDisplay("{CharacterCode} - '{Char}': {GlyphIndex}")] + public class GlyphMapping : FontTableElement + { + public ushort CharacterCode { get; set; } + + public ushort GlyphIndex { get; set; } + + public char Char => Convert.ToChar(CharacterCode); + + public override string ToString() + { + return Char.ToString() + ": " + GlyphIndex; + } + + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(CharacterCode); + writer.WriteUInt16BigEndian(GlyphIndex); + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CharGlyphPair.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CharGlyphPair.cs new file mode 100644 index 0000000000..962e8b80c0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CharGlyphPair.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Mappings +{ + internal class CharGlyphPair + { + public uint CharCode { get; set; } + public ushort GlyphIndex { get; set; } + + public CharGlyphPair(uint charCode, ushort glyphIndex) + { + CharCode = charCode; + GlyphIndex = glyphIndex; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CmapFormat4.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CmapFormat4.cs new file mode 100644 index 0000000000..dce1777b4a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/CmapFormat4.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Mappings +{ + internal static class CmapFormat4 + { + /// + /// Creates a minimal and correct Format 4 cmap subtable from a dictionary of Unicode code points to glyph IDs. + /// Optimized for font subsetting – only includes used characters and guarantees .notdef (code point 0 to glyph 0). + /// Fully compatible with .NET 3.5 and EPPlus coding standards. + /// + /// Mapping of Unicode code points to new (subset) glyph IDs + /// A fully populated CmapSubtable4 ready for serialization + internal static CmapSubtable4 CreateFromMappings(Dictionary codePointToGlyphId) + { + if (codePointToGlyphId == null || codePointToGlyphId.Count == 0) + throw new ArgumentException("No character-to-glyph mappings provided.", "codePointToGlyphId"); + + // Ensure .notdef mapping exists (U+0000 to glyph 0) + codePointToGlyphId[0] = 0; + + // Sort code points for sequential processing + List sortedCodes = new List(codePointToGlyphId.Keys); + sortedCodes.Sort(); + + // Temporary lists to build segments + List segStart = new List(); + List segEnd = new List(); + List segDelta = new List(); + List segRangeOffset = new List(); + List glyphIdArray = new List(); + + uint currentStart = sortedCodes[0]; + uint currentEnd = sortedCodes[0]; + ushort currentFirstGlyph = codePointToGlyphId[currentStart]; + + for (int i = 1; i < sortedCodes.Count; i++) + { + uint code = sortedCodes[i]; + ushort glyph = codePointToGlyphId[code]; + + if (code == currentEnd + 1 && glyph == (ushort)(currentFirstGlyph + (code - currentStart))) + { + // Continue current segment + currentEnd = code; + } + else + { + // Finalize current segment + AddSegment(segStart, segEnd, segDelta, segRangeOffset, glyphIdArray, + currentStart, currentEnd, currentFirstGlyph, codePointToGlyphId); + + // Start new segment + currentStart = code; + currentEnd = code; + currentFirstGlyph = glyph; + } + } + + // Add final segment + AddSegment(segStart, segEnd, segDelta, segRangeOffset, glyphIdArray, + currentStart, currentEnd, currentFirstGlyph, codePointToGlyphId); + + // Add terminating segment (0xFFFF) + segStart.Add(0xFFFF); + segEnd.Add(0xFFFF); + segDelta.Add(1); // 0xFFFF + 1 to glyph 0 + segRangeOffset.Add(0); + + int segCount = segStart.Count; + + // Calculate search parameters + int pow2 = 1; + while (pow2 * 2 <= segCount) pow2 *= 2; + ushort searchRange = (ushort)(pow2 * 2); + ushort entrySelector = 0; + int temp = pow2; + while (temp > 1) + { + temp /= 2; + entrySelector++; + } + ushort rangeShift = (ushort)(segCount * 2 - searchRange); + + // Calculate correct table length (header + data + 4-byte alignment) + int headerSize = 16; // format(2) + length(2) + language(2) + segCountX2(2) + searchRange(2) + entrySelector(2) + rangeShift(2) + int segmentDataSize = segCount * 8; // endCode, startCode, idDelta, idRangeOffset – 2 bytes each × segCount + int glyphIdArraySize = glyphIdArray.Count * 2; + int totalSize = headerSize + segmentDataSize + glyphIdArraySize; + + // 4-byte alignment required by OpenType spec + int paddedSize = (totalSize + 3) & ~3; + + return new CmapSubtable4 + { + SegCountX2 = (ushort)(segCount * 2), + SearchRange = searchRange, + EntrySelector = entrySelector, + RangeShift = rangeShift, + EndCode = segEnd.ToArray(), + ReservedPad = 0, + StartCode = segStart.ToArray(), + IdDelta = segDelta.ToArray(), + IdRangeOffset = segRangeOffset.ToArray(), + GlyphIdArray = glyphIdArray.ToArray(), + Length = (uint)paddedSize + }; + } + + // Helper: adds one segment to the format 4 arrays + // I klassen: internal static class CmapFormat4 + // Ersätt hela den befintliga AddSegment-metoden med denna: + + private static void AddSegment( + List startCodes, + List endCodes, + List deltas, + List rangeOffsets, + List glyphIdArray, + uint startCode, + uint endCode, + ushort firstGlyphId, + Dictionary mapping) + { + startCodes.Add((ushort)startCode); + endCodes.Add((ushort)endCode); + + // Försök använda idDelta (sekventiell mappning) + bool isSequential = true; + for (uint c = startCode; c <= endCode; c++) + { + ushort expectedGlyph = (ushort)((firstGlyphId + (c - startCode)) & 0xFFFF); + if (mapping[c] != expectedGlyph) + { + isSequential = false; + break; + } + } + + if (isSequential) + { + // Sekventiell → använd bara idDelta + short delta = (short)((int)firstGlyphId - (int)startCode); + deltas.Add(delta); + rangeOffsets.Add(0); + } + else + { + // Icke-sekventiell → använd glyphIdArray + int glyphArrayStartIndex = glyphIdArray.Count; + + // Lägg till alla glyph-ID:n för detta segment + for (uint c = startCode; c <= endCode; c++) + { + glyphIdArray.Add(mapping[c]); + } + + // RÄTT BERÄKNING AV idRangeOffset (detta var felet!) + // Avstånd i bytes från denna idRangeOffset-post till glyphIdArray[startCode] + int entriesFromThisIncludingThis = rangeOffsets.Count + 1; + int idRangeOffset = entriesFromThisIncludingThis * 2 + (glyphIdArray.Count - glyphArrayStartIndex) * 2 - 2; + + deltas.Add(0); // idDelta ignoreras när idRangeOffset != 0 + rangeOffsets.Add((ushort)idRangeOffset); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/GlyphMappings.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/GlyphMappings.cs new file mode 100644 index 0000000000..7fb9ce3725 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Mappings/GlyphMappings.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Mappings +{ + + public class GlyphMappings + { + public Dictionary CharCodeToGlyphIndex { get; } = new(); + public Dictionary> GlyphIndexToCharCodes { get; } = new(); + + public void AddMapping(uint charCode, ushort glyphIndex) + { + CharCodeToGlyphIndex[charCode] = glyphIndex; + + if (!GlyphIndexToCharCodes.TryGetValue(glyphIndex, out var list)) + { + list = new List(); + GlyphIndexToCharCodes[glyphIndex] = list; + } + list.Add(charCode); + } + + public ushort? GetGlyphIndex(uint charCode) + => CharCodeToGlyphIndex.TryGetValue(charCode, out var glyphIndex) ? glyphIndex : null; + + public IEnumerable GetCharCodes(ushort glyphIndex) + => GlyphIndexToCharCodes.TryGetValue(glyphIndex, out var codes) ? codes : Enumerable.Empty(); + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/NonDefaultUvsTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/NonDefaultUvsTable.cs new file mode 100644 index 0000000000..0fbe6c9e8b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/NonDefaultUvsTable.cs @@ -0,0 +1,36 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + + public class NonDefaultUvsTable : FontTableElement + { + public List Mappings { get; internal set; } = new(); + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt32BigEndian((uint)Mappings.Count); + + foreach (var mapping in Mappings) + { + mapping.Serialize(writer); + } + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Platforms.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Platforms.cs new file mode 100644 index 0000000000..f185543f17 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Platforms.cs @@ -0,0 +1,23 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public enum Platforms : ushort + { + Unicode = 0, + Macintosh = 1, + ISO_Deprecated = 2, + Windows = 3, + Custom = 4 + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/SequencialMapGroup.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/SequencialMapGroup.cs new file mode 100644 index 0000000000..8fa8252167 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/SequencialMapGroup.cs @@ -0,0 +1,35 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class SequencialMapGroup : FontTableElement + { + public uint StartCharCode { get; internal set; } + + public uint EndCharCode { get; internal set; } + + public uint StartGlyphId { get; internal set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt32BigEndian(StartCharCode); + writer.WriteUInt32BigEndian(EndCharCode); + writer.WriteUInt32BigEndian(StartGlyphId); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Deserializer.cs new file mode 100644 index 0000000000..387c250d0a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Deserializer.cs @@ -0,0 +1,52 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable0Deserializer + { + private readonly FontsBinaryReader _reader; + + public CmapSubtable0Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public CmapSubtable0 Deserialize(uint startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + + // Read and validate the format field(must be 0 for format 0) + var format = _reader.ReadUInt16BigEndian(); + if (format != 0) + throw new InvalidDataException($"Unexpected cmap subtable format: {format} (expected 0)."); + + var table = new CmapSubtable0 + { + Length = _reader.ReadUInt16BigEndian(), + Language = _reader.ReadUInt16BigEndian() + }; + + // Format 0 requires exactly 256 bytes in the glyphIdArray. + const int GlyphArrayLength = 256; + var glyphBytes = _reader.ReadBytes(GlyphArrayLength); + if (glyphBytes == null || glyphBytes.Length != GlyphArrayLength) + throw new EndOfStreamException("Not enough data to read glyphIdArray for cmap format 0."); + + table.GlyphIdArray = glyphBytes; + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Serializer.cs new file mode 100644 index 0000000000..af545a6dfd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable0Serializer.cs @@ -0,0 +1,43 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable02Serializer + { + public void Serialize(CmapSubtable0 table, FontsBinaryWriter writer) + { + // Format 0 requires exactly 256 bytes in the glyphIdArray + if (table.GlyphIdArray == null || table.GlyphIdArray.Length != 256) + throw new InvalidOperationException("GlyphIdArray must contain exactly 256 entries for format 0."); + + // Format 0 has a fixed length: 6 bytes header + 256 bytes glyphIdArray = 262 bytes + if (table.Length == 0) + table.Length = 262; + + // Write the format (always 0) + writer.WriteUInt16BigEndian(table.Format); + + // Write the total length of the subtable + writer.WriteUInt16BigEndian((ushort)table.Length); + + // Write the language field + writer.WriteUInt16BigEndian((ushort)table.Language); + + // Write the 256-byte glyphIdArray + writer.Write(table.GlyphIdArray); + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Deserializer.cs new file mode 100644 index 0000000000..53b2f9b15f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Deserializer.cs @@ -0,0 +1,52 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable12Deserializer + { + private readonly FontsBinaryReader _reader; + + public CmapSubtable12Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public CmapSubtable12 Deserialize(uint startIndex) + { + _reader.BaseStream.Position = startIndex; + + var subtable = new CmapSubtable12(); + + // Read header + var format = _reader.ReadUInt16BigEndian(); // should always be 12 + var reserved = _reader.ReadUInt16BigEndian(); // always 0 + subtable.Length = _reader.ReadUInt32BigEndian(); + subtable.Language = _reader.ReadUInt32BigEndian(); + subtable.NumGroups = _reader.ReadUInt32BigEndian(); + + // Read groups + for (int i = 0; i < subtable.NumGroups; i++) + { + var group = new SequencialMapGroup + { + StartCharCode = _reader.ReadUInt32BigEndian(), + EndCharCode = _reader.ReadUInt32BigEndian(), + StartGlyphId = _reader.ReadUInt32BigEndian() + }; + subtable.Groups.Add(group); + } + + return subtable; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Serializer.cs new file mode 100644 index 0000000000..345a6b21b2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable12Serializer.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable12Serializer : CmapSubtableSerializerBase + { + internal override void Serialize(CmapSubtable12 subTable, FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(subTable.Format); + writer.WriteUInt16BigEndian(subTable.Reserved); + writer.WriteUInt32BigEndian(subTable.Length); + writer.WriteUInt32BigEndian(subTable.Language); + writer.WriteUInt32BigEndian(subTable.NumGroups); + + foreach (var group in subTable.Groups) + { + group.Serialize(writer); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Deserializer.cs new file mode 100644 index 0000000000..70880f90dc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Deserializer.cs @@ -0,0 +1,110 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable14Deserializer + { + private readonly FontsBinaryReader _reader; + + public CmapSubtable14Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + internal CmapSubtable14 Deserialize(uint startIndex) + { + // Move to the start of the subtable + _reader.BaseStream.Position = startIndex; + long startOffset = _reader.BaseStream.Position; + + // Read header + ushort format = _reader.ReadUInt16BigEndian(); // Should be 14 + if (format != 14) + throw new InvalidDataException("Expected format 14"); + + uint length = _reader.ReadUInt32BigEndian(); + uint numVarSelectorRecords = _reader.ReadUInt32BigEndian(); + + var subtable = new CmapSubtable14 + { + Length = length, + Language = 0 // Format 14 does not use language + }; + + // Read all VariationSelector records + for (int i = 0; i < numVarSelectorRecords; i++) + { + uint varSelector = _reader.ReadUInt24BigEndian(); + uint defaultUVSOffset = _reader.ReadUInt32BigEndian(); + uint nonDefaultUVSOffset = _reader.ReadUInt32BigEndian(); + + var selector = new VariationSelector + { + VarSelector = varSelector, + DefaultUVSOffset = defaultUVSOffset, + NonDefaultUVSOffset = nonDefaultUVSOffset + }; + + // Read Default UVS Table if present + if (defaultUVSOffset != 0) + { + _reader.BaseStream.Position = startOffset + defaultUVSOffset; + uint numRanges = _reader.ReadUInt32BigEndian(); + + var defaultTable = new DefaultUvsTable(); + for (int j = 0; j < numRanges; j++) + { + var range = new UnicodeRange + { + StartUnicodeValue = _reader.ReadUInt24BigEndian(), + AdditionalCount = _reader.ReadByte() + }; + defaultTable.Ranges.Add(range); + } + + selector.DefaultUvsTable = defaultTable; + } + + // Read Non-Default UVS Table if present + if (nonDefaultUVSOffset != 0) + { + _reader.BaseStream.Position = startOffset + nonDefaultUVSOffset; + uint numMappings = _reader.ReadUInt32BigEndian(); + + var nonDefaultTable = new NonDefaultUvsTable(); + for (int j = 0; j < numMappings; j++) + { + var mapping = new UvsMapping + { + UnicodeValue = _reader.ReadUInt24BigEndian(), + GlyphId = _reader.ReadUInt16BigEndian() + }; + nonDefaultTable.Mappings.Add(mapping); + } + + selector.NonDefaultUvsTable = nonDefaultTable; + } + + subtable.VariationSelectors.Add(selector); + } + + return subtable; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Serializer.cs new file mode 100644 index 0000000000..1bd8808497 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable14Serializer.cs @@ -0,0 +1,96 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable14Serializer : CmapSubtableSerializerBase + { + internal override void Serialize(CmapSubtable14 subTable, FontsBinaryWriter writer) + { + // Save the starting position of the subtable in the stream + long startOffset = writer.BaseStream.Position; + + // Write the header: + // Format (2 bytes), Length (4 bytes placeholder), Number of VariationSelector records (4 bytes) + writer.WriteUInt16BigEndian(subTable.Format); // Format = 14 + writer.WriteUInt32BigEndian(0); // Placeholder for Length + writer.WriteUInt32BigEndian((uint)subTable.VariationSelectors.Count); + + // Store the positions where we will later write the DefaultUVSOffset and NonDefaultUVSOffset + var selectorOffsetPositions = new List(); + + // Write each VariationSelector record with placeholder offsets + foreach (var selector in subTable.VariationSelectors) + { + writer.WriteUInt24BigEndian(selector.VarSelector); + + // Save the position where the offsets will be written + selectorOffsetPositions.Add(writer.BaseStream.Position); + + writer.WriteUInt32BigEndian(0); // DefaultUVSOffset placeholder + writer.WriteUInt32BigEndian(0); // NonDefaultUVSOffset placeholder + } + + // Write UVS tables and record their offsets + for (int i = 0; i < subTable.VariationSelectors.Count; i++) + { + var selector = subTable.VariationSelectors[i]; + + // Write Default UVS Table if present + if (selector.DefaultUvsTable != null && selector.DefaultUvsTable.Ranges.Count > 0) + { + long offset = writer.BaseStream.Position - startOffset; + selector.DefaultUVSOffset = (uint)offset; + selector.DefaultUvsTable.Serialize(writer); + } + + // Write Non-Default UVS Table if present + if (selector.NonDefaultUvsTable != null && selector.NonDefaultUvsTable.Mappings.Count > 0) + { + long offset = writer.BaseStream.Position - startOffset; + selector.NonDefaultUVSOffset = (uint)offset; + selector.NonDefaultUvsTable.Serialize(writer); + } + + // Go back and write the correct offsets into the selector record + long offsetPos = selectorOffsetPositions[i]; + long currentPos = writer.BaseStream.Position; + + writer.BaseStream.Position = offsetPos; + writer.WriteUInt32BigEndian(selector.DefaultUVSOffset); + writer.WriteUInt32BigEndian(selector.NonDefaultUVSOffset); + + // Return to the current position to continue writing + writer.BaseStream.Position = currentPos; + } + + // Calculate and update the total length of the subtable + long endOffset = writer.BaseStream.Position; + subTable.Length = (uint)(endOffset - startOffset); + + // Go back and write the correct length into the header + long lengthPos = startOffset + 2; // Length field starts after Format (2 bytes) + long finalPos = writer.BaseStream.Position; + + writer.BaseStream.Position = lengthPos; + writer.WriteUInt32BigEndian(subTable.Length); + + // Return to the end of the stream + writer.BaseStream.Position = finalPos; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Deserializer.cs new file mode 100644 index 0000000000..86c3d418f5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Deserializer.cs @@ -0,0 +1,66 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable4Deserializer + { + public CmapSubtable4Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + private readonly FontsBinaryReader _reader; + + + public CmapSubtable4 Deserialize(uint startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + + var format = _reader.ReadUInt16BigEndian(); + + var table = new CmapSubtable4 + { + Length = _reader.ReadUInt16BigEndian(), + Language = _reader.ReadUInt16BigEndian(), + SegCountX2 = _reader.ReadUInt16BigEndian(), + SearchRange = _reader.ReadUInt16BigEndian(), + EntrySelector = _reader.ReadUInt16BigEndian(), + RangeShift = _reader.ReadUInt16BigEndian() + }; + + int segCount = table.SegCountX2 / 2; + + table.EndCode = _reader.ReadUInt16ArrayBigEndian(segCount); + table.ReservedPad = _reader.ReadUInt16BigEndian(); + table.StartCode = _reader.ReadUInt16ArrayBigEndian(segCount); + table.IdDelta = _reader.ReadInt16ArrayBigEndian(segCount); + table.IdRangeOffset = _reader.ReadUInt16ArrayBigEndian(segCount); + + int bytesRead = 14 + segCount * 8 + 2; + int glyphArrayBytes = (ushort)table.Length - bytesRead; + int glyphCount = glyphArrayBytes / 2; + + table.GlyphIdArray = _reader.ReadUInt16ArrayBigEndian(glyphCount); + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Serializer.cs new file mode 100644 index 0000000000..b4b140b996 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable4Serializer.cs @@ -0,0 +1,50 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable4Serializer + { + public void Serialize(CmapSubtable4 table, FontsBinaryWriter writer) + { + // Write header fields + writer.WriteUInt16BigEndian(table.Format); + writer.WriteUInt16BigEndian((ushort)table.Length); + writer.WriteUInt16BigEndian((ushort)table.Language); + writer.WriteUInt16BigEndian(table.SegCountX2); + writer.WriteUInt16BigEndian(table.SearchRange); + writer.WriteUInt16BigEndian(table.EntrySelector); + writer.WriteUInt16BigEndian(table.RangeShift); + + int segCount = table.SegCountX2 / 2; + + // Write segment arrays + for (int i = 0; i < segCount; i++) + writer.WriteUInt16BigEndian(table.EndCode[i]); + + writer.WriteUInt16BigEndian(table.ReservedPad); + + for (int i = 0; i < segCount; i++) + writer.WriteUInt16BigEndian(table.StartCode[i]); + + for (int i = 0; i < segCount; i++) + writer.WriteInt16BigEndian(table.IdDelta[i]); + + for (int i = 0; i < segCount; i++) + writer.WriteUInt16BigEndian(table.IdRangeOffset[i]); + + // Write glyphIdArray + for (int i = 0; i < table.GlyphIdArray.Length; i++) + writer.WriteUInt16BigEndian(table.GlyphIdArray[i]); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable62Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable62Deserializer.cs new file mode 100644 index 0000000000..b3fd416d6e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable62Deserializer.cs @@ -0,0 +1,59 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable6Deserializer + { + private readonly FontsBinaryReader _reader; + + public CmapSubtable6Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public CmapSubtable6 Deserialize(uint startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + + // Read format field and ensure we are at the expected subtable + var format = _reader.ReadUInt16BigEndian(); + if (format != 6) + throw new InvalidDataException($"Unexpected cmap subtable format: {format} (expected 6)."); + + var table = new CmapSubtable6 + { + Length = _reader.ReadUInt16BigEndian(), + Language = _reader.ReadUInt16BigEndian(), + FirstCode = _reader.ReadUInt16BigEndian(), + EntryCount = _reader.ReadUInt16BigEndian() + }; + + if (table.EntryCount > 0) + { + // Read exactly EntryCount entries; if stream is truncated, let ReadUInt16ArrayBigEndian throw/end up as EndOfStreamException + table.GlyphIdArray = _reader.ReadUInt16ArrayBigEndian(table.EntryCount) ?? new ushort[0]; + + if (table.GlyphIdArray.Length != table.EntryCount) + throw new EndOfStreamException("Not enough data to read glyphIdArray for cmap format 6."); + } + else + { + table.GlyphIdArray = new ushort[0]; + } + + return table; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6Serializer.cs new file mode 100644 index 0000000000..e5af07f326 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6Serializer.cs @@ -0,0 +1,65 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable6Serializer : CmapSubtableSerializerBase + { + internal override void Serialize(CmapSubtable6 subTable, FontsBinaryWriter writer) + { + // Format 6 header fields: + // format (2 bytes) = 6 + // length (2 bytes) = 6 + 2 + 2 + 2 * entryCount = 10 + 2 * entryCount + // language (2 bytes) + // firstCode (2 bytes) + // entryCount (2 bytes) + // glyphIdArray (2 bytes * entryCount) + + //if (subTable.GlyphMappingArray == null || subTable.GlyphMappingArray.Length == 0) + //{ + // throw new InvalidOperationException("GlyphMappingArray is empty. Cannot serialize CmapSubtable6."); + //} + + //// Determine firstCode and entryCount + //ushort firstCode = subTable.GlyphMappingArray.Min(g => g.CharacterCode); + //ushort lastCode = subTable.GlyphMappingArray.Max(g => g.CharacterCode); + //ushort entryCount = (ushort)(lastCode - firstCode + 1); + + //// Build glyphIdArray with default value 0 + //ushort[] glyphIdArray = new ushort[entryCount]; + //foreach (var mapping in subTable.GlyphMappingArray) + //{ + // int index = mapping.CharacterCode - firstCode; + // glyphIdArray[index] = mapping.GlyphIndex; + //} + + //// Calculate total length + //ushort length = (ushort)(10 + entryCount * 2); + + //// Write header + //writer.WriteUInt16BigEndian(subTable.Format); // format = 6 + //writer.WriteUInt16BigEndian(length); // total length + //writer.WriteUInt16BigEndian(subTable.Language); // language + //writer.WriteUInt16BigEndian(firstCode); // first character code + //writer.WriteUInt16BigEndian(entryCount); // number of entries + + //// Write glyphIdArray + //foreach (var glyphIndex in glyphIdArray) + //{ + // writer.WriteUInt16BigEndian(glyphIndex); + //} + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6_2Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6_2Serializer.cs new file mode 100644 index 0000000000..e1ca4bfd6d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtable6_2Serializer.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal class CmapSubtable6_2Serializer + { + public void Serialize(CmapSubtable6 table, FontsBinaryWriter writer) + { + if (table.GlyphIdArray == null || table.GlyphIdArray.Length != table.EntryCount) + throw new InvalidOperationException("GlyphIdArray length must match EntryCount."); + + // Format 6 length = 10 bytes header + 2 * entryCount + if (table.Length == 0) + table.Length = (ushort)(10 + 2 * table.EntryCount); + + writer.WriteUInt16BigEndian(table.Format); + writer.WriteUInt16BigEndian((ushort)table.Length); + writer.WriteUInt16BigEndian((ushort)table.Language); + writer.WriteUInt16BigEndian(table.FirstCode); + writer.WriteUInt16BigEndian(table.EntryCount); + + for (int i = 0; i < table.EntryCount; i++) + writer.WriteUInt16BigEndian(table.GlyphIdArray[i]); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtableSerializerBase.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtableSerializerBase.cs new file mode 100644 index 0000000000..fb84ff8bd4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/Serialization/CmapSubtableSerializerBase.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap.Serialization +{ + internal abstract class CmapSubtableSerializerBase + where T : CmapSubtableBase + { + internal abstract void Serialize(T subTable, FontsBinaryWriter writer); + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/UnicodeRange.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/UnicodeRange.cs new file mode 100644 index 0000000000..427d63dfc8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/UnicodeRange.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class UnicodeRange : FontTableElement + { + public uint StartUnicodeValue { get; internal set; } + public byte AdditionalCount { get; internal set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt24BigEndian(StartUnicodeValue); + writer.Write(AdditionalCount); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/UvsMapping.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/UvsMapping.cs new file mode 100644 index 0000000000..72dd0c4547 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/UvsMapping.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + + public class UvsMapping : FontTableElement + { + public uint UnicodeValue { get; internal set; } + public ushort GlyphId { get; internal set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt24BigEndian(UnicodeValue); + writer.WriteUInt16BigEndian(GlyphId); + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Cmap/VariationSelector.cs b/src/EPPlus.Fonts.OpenType/Tables/Cmap/VariationSelector.cs new file mode 100644 index 0000000000..ef40ce8e19 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Cmap/VariationSelector.cs @@ -0,0 +1,36 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Cmap +{ + public class VariationSelector : FontTableElement + { + public uint VarSelector { get; internal set; } // 24-bit värde + public uint DefaultUVSOffset { get; internal set; } + public uint NonDefaultUVSOffset { get; internal set; } + + public DefaultUvsTable DefaultUvsTable { get; internal set; } + public NonDefaultUvsTable NonDefaultUvsTable { get; internal set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt24BigEndian(VarSelector); + writer.WriteUInt32BigEndian(DefaultUVSOffset); + writer.WriteUInt32BigEndian(NonDefaultUVSOffset); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat1.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat1.cs new file mode 100644 index 0000000000..27cf95aff3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat1.cs @@ -0,0 +1,53 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef +{ + public class ClassDefFormat1 : ClassDefTable + { + public ushort StartGlyphID { get; set; } + public ushort GlyphCount { get; set; } + public ushort[] ClassValueArray { get; set; } + + public ClassDefFormat1() + { + Format = 1; + } + + public override int GetClass(ushort glyphId) + { + int index = glyphId - StartGlyphID; + if (index < 0 || index >= GlyphCount) + return 0; + + if (ClassValueArray == null || index >= ClassValueArray.Length) + return 0; + + return ClassValueArray[index]; + } + + internal override void SerializeBody(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(StartGlyphID); + writer.WriteUInt16BigEndian(GlyphCount); + + for (int i = 0; i < GlyphCount; i++) + { + ushort v = 0; + if (ClassValueArray != null && i < ClassValueArray.Length) + v = ClassValueArray[i]; + + writer.WriteUInt16BigEndian(v); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat2.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat2.cs new file mode 100644 index 0000000000..95992f2458 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefFormat2.cs @@ -0,0 +1,72 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef +{ + public class ClassDefFormat2 : ClassDefTable + { + public List ClassRangeRecords { get; set; } + + public ClassDefFormat2() + { + Format = 2; + } + + public override int GetClass(ushort glyphId) + { + if (ClassRangeRecords == null || ClassRangeRecords.Count == 0) + return 0; + + // Binary search through ranges + // ClassRangeRecords MUST be sorted by StartGlyphID per OpenType spec + int left = 0; + int right = ClassRangeRecords.Count - 1; + + while (left <= right) + { + int mid = left + (right - left) / 2; + var range = ClassRangeRecords[mid]; + + // Check if glyphId is in this range + if (glyphId >= range.StartGlyphID && glyphId <= range.EndGlyphID) + return range.Class; + + // Search left half + if (glyphId < range.StartGlyphID) + right = mid - 1; + // Search right half + else + left = mid + 1; + } + + return 0; // Not found - default class + } + + internal override void SerializeBody(FontsBinaryWriter writer) + { + ushort count = (ushort)(ClassRangeRecords?.Count ?? 0); + writer.WriteUInt16BigEndian(count); + + if (ClassRangeRecords != null) + { + foreach (var r in ClassRangeRecords) + { + writer.WriteUInt16BigEndian(r.StartGlyphID); + writer.WriteUInt16BigEndian(r.EndGlyphID); + writer.WriteUInt16BigEndian(r.Class); + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefTable.cs new file mode 100644 index 0000000000..704e7090f5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassDefTable.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef +{ + /// + /// Base class for ClassDef subtables (Format 1 and Format 2). + /// Defines the common API and serialization entry point. + /// + public abstract class ClassDefTable : FontTableElement + { + /// + /// ClassDef format (1 or 2). + /// + public ushort Format { get; protected set; } + + /// + /// Returns the class value for a given glyph ID. + /// + public abstract int GetClass(ushort glyphId); + + /// + /// Writes the ClassDef table to the stream. + /// Subclasses implement the actual body. + /// + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(Format); + SerializeBody(writer); + } + + /// + /// Subclasses implement the format-specific serialization. + /// + internal abstract void SerializeBody(FontsBinaryWriter writer); + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassRangeRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassRangeRecord.cs new file mode 100644 index 0000000000..e11b1b469e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/ClassRangeRecord.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef +{ + /// + /// Represents a single ClassRangeRecord in a ClassDef Format 2 table. + /// Maps a continuous glyph ID range to a class value. + /// + public class ClassRangeRecord + { + /// + /// First glyph ID in the range (inclusive). + /// + public ushort StartGlyphID { get; set; } + + /// + /// Last glyph ID in the range (inclusive). + /// + public ushort EndGlyphID { get; set; } + + /// + /// Class value assigned to all glyphs in [StartGlyphID, EndGlyphID]. + /// + public ushort Class { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/IO/ClassDefTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/IO/ClassDefTableDeserializer.cs new file mode 100644 index 0000000000..0ab908499a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/ClassDef/IO/ClassDefTableDeserializer.cs @@ -0,0 +1,104 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 16/01/2026 EPPlus Software AB ClassDef deserializer (Format 1 & 2) + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef.IO +{ + /// + /// Deserializes ClassDef tables (Format 1 and 2) from OpenType fonts. + /// Shared between GSUB and GPOS. + /// + internal class ClassDefTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public ClassDefTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + /// + /// Deserializes a ClassDef table at the given absolute offset. + /// + /// Absolute byte offset where the ClassDef table starts. + public ClassDefTable Deserialize(long classDefStart) + { + _reader.BaseStream.Seek(classDefStart, SeekOrigin.Begin); + + ushort format = _reader.ReadUInt16BigEndian(); + + if (format == 1) + { + return ReadFormat1(classDefStart); + } + else if (format == 2) + { + return ReadFormat2(classDefStart); + } + + // Okänt format – returnera null eller kasta om du vill vara strikt + return null; + } + + private ClassDefTable ReadFormat1(long classDefStart) + { + // Format 1: + // USHORT ClassFormat (already read) + // USHORT StartGlyphID + // USHORT GlyphCount + // USHORT ClassValueArray[GlyphCount] + + var table = new ClassDefFormat1 + { + StartGlyphID = _reader.ReadUInt16BigEndian(), + GlyphCount = _reader.ReadUInt16BigEndian() + }; + + table.ClassValueArray = new ushort[table.GlyphCount]; + for (int i = 0; i < table.GlyphCount; i++) + { + table.ClassValueArray[i] = _reader.ReadUInt16BigEndian(); + } + + return table; + } + + private ClassDefTable ReadFormat2(long classDefStart) + { + // Format 2: + // USHORT ClassFormat (already read) + // USHORT ClassRangeCount + // ClassRangeRecord ClassRangeRecord[ClassRangeCount] + + var table = new ClassDefFormat2(); + + ushort classRangeCount = _reader.ReadUInt16BigEndian(); + table.ClassRangeRecords = new List(classRangeCount); + + for (int i = 0; i < classRangeCount; i++) + { + var rec = new ClassRangeRecord + { + StartGlyphID = _reader.ReadUInt16BigEndian(), + EndGlyphID = _reader.ReadUInt16BigEndian(), + Class = _reader.ReadUInt16BigEndian() + }; + + table.ClassRangeRecords.Add(rec); + } + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageRangeRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageRangeRecord.cs new file mode 100644 index 0000000000..0f024d4a88 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageRangeRecord.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage +{ + public class CoverageRangeRecord : FontTableElement + { + public ushort StartGlyphID { get; set; } + public ushort EndGlyphID { get; set; } + public ushort StartCoverageIndex { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTable.cs new file mode 100644 index 0000000000..802a798316 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTable.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage +{ + public abstract class CoverageTable : FontTableElement + { + public ushort CoverageFormat { get; set; } + public abstract ushort[] CoveredGlyphs { get; } + + public abstract int GetGlyphIndex(ushort glyphId); + + public abstract ushort[] GetCoveredGlyphs(); + + /// + /// Checks if a glyph ID is covered by this coverage table. + /// + /// The glyph ID to check + /// True if the glyph is covered, false otherwise + public bool IsCovered(ushort glyphId) + { + return GetGlyphIndex(glyphId) >= 0; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat1.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat1.cs new file mode 100644 index 0000000000..f10998c8d8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat1.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using EPPlus.Fonts.OpenType.Tables.Gsub.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage +{ + public class CoverageTableFormat1 : CoverageTable + { + public ushort GlyphCount { get; set; } + public ushort[] GlyphArray { get; set; } + public override ushort[] CoveredGlyphs => GlyphArray; + + public override ushort[] GetCoveredGlyphs() + { + // Format 1 is already a flat array + return GlyphArray ?? new ushort[0]; + } + + public override int GetGlyphIndex(ushort glyphId) + { + if (GlyphArray == null || GlyphArray.Length == 0) return -1; + + // Binary search is efficient as GlyphArray MUST be sorted ascending + int low = 0; + int high = GlyphArray.Length - 1; + + while (low <= high) + { + int mid = low + (high - low) / 2; + ushort midVal = GlyphArray[mid]; + + if (midVal == glyphId) return mid; + if (midVal < glyphId) low = mid + 1; + else high = mid - 1; + } + + return -1; // Not found + } + + internal override void Serialize(FontsBinaryWriter writer) + { + new CoverageTableFormat1Serializer().Serialize(this, writer); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat2.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat2.cs new file mode 100644 index 0000000000..71fcd51515 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/CoverageTableFormat2.cs @@ -0,0 +1,165 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage +{ + /// + /// Represents a Coverage Table Format 2, which defines glyph coverage using ranges. + /// + public class CoverageTableFormat2 : CoverageTable + { + /// + /// Gets or sets the number of range records. + /// + public ushort RangeCount { get; set; } + + /// + /// Gets or sets the list of range records defining the covered glyphs. + /// + public List RangeRecords { get; set; } = new List(); + + /// + /// Gets an array of all Glyph IDs covered by this table. + /// + public override ushort[] CoveredGlyphs + { + get + { + return GetCoveredGlyphs(); + } + } + + /// + /// Returns the coverage index for a specific Glyph ID. + /// + /// The Glyph ID to look up. + /// The coverage index, or -1 if the glyph is not covered. + public override int GetGlyphIndex(ushort glyphId) + { + if (RangeRecords == null || RangeRecords.Count == 0) return -1; + + // Binary search through the ranges for performance (O(log n)) + int low = 0; + int high = RangeRecords.Count - 1; + + while (low <= high) + { + int mid = low + (high - low) / 2; + var range = RangeRecords[mid]; + + if (glyphId >= range.StartGlyphID && glyphId <= range.EndGlyphID) + { + // The Coverage Index is calculated as: StartCoverageIndex + (GlyphID - StartGlyphID) + return range.StartCoverageIndex + (glyphId - range.StartGlyphID); + } + + if (glyphId < range.StartGlyphID) + { + high = mid - 1; + } + else + { + low = mid + 1; + } + } + + return -1; // Glyph ID not found in any range + } + + /// + /// Generates an array of all covered Glyph IDs by flattening the range records. + /// + public override ushort[] GetCoveredGlyphs() + { + if (RangeRecords == null) return new ushort[0]; + + // Uses SelectMany to flatten the ranges produced by GetRange + return RangeRecords.SelectMany(r => GetRange(r.StartGlyphID, r.EndGlyphID)).ToArray(); + } + + /// + /// Helper to generate a sequence of Glyph IDs between start and end inclusive. + /// Compatible with .NET 3.5. + /// + private IEnumerable GetRange(ushort start, ushort end) + { + if (start > end) + { + yield break; + } + + for (int i = start; i <= end; i++) + { + yield return (ushort)i; + } + } + + internal override void Serialize(FontsBinaryWriter writer) + { + new CoverageTableFormat2Serializer().Serialize(this, writer); + } + + /// + /// Factory method to create a Format 2 Coverage Table from a list of sorted Glyph IDs. + /// This method automatically groups consecutive IDs into ranges to optimize size. + /// + /// A sorted list of Glyph IDs. + internal static CoverageTableFormat2 CreateCoverageFormat2(List newGlyphs) + { + CoverageTableFormat2 coverage = new CoverageTableFormat2(); + if (newGlyphs == null || newGlyphs.Count == 0) + { + coverage.RangeCount = 0; + return coverage; + } + + ushort startGlyph = newGlyphs[0]; + ushort lastGlyph = newGlyphs[0]; + ushort startCoverageIndex = 0; + + for (int i = 1; i <= newGlyphs.Count; i++) + { + // Close the current range if: + // 1. We reached the end of the list + // 2. The current GID is not consecutive (there is a gap) + if (i == newGlyphs.Count || newGlyphs[i] != lastGlyph + 1) + { + coverage.RangeRecords.Add(new CoverageRangeRecord + { + StartGlyphID = startGlyph, + EndGlyphID = lastGlyph, + StartCoverageIndex = startCoverageIndex + }); + + if (i < newGlyphs.Count) + { + startGlyph = newGlyphs[i]; + lastGlyph = newGlyphs[i]; + // The next coverage index is the number of glyphs processed so far + startCoverageIndex = (ushort)i; + } + } + else + { + lastGlyph = newGlyphs[i]; + } + } + + coverage.RangeCount = (ushort)coverage.RangeRecords.Count; + return coverage; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Deserializer.cs new file mode 100644 index 0000000000..c94f686eef --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Deserializer.cs @@ -0,0 +1,50 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO +{ + internal class CoverageTableFormat1Deserializer + { + private readonly FontsBinaryReader _reader; + + public CoverageTableFormat1Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public CoverageTableFormat1 Deserialize(long startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + + // Read Format (already known to be 1, but read to advance position) + ushort format = _reader.ReadUInt16BigEndian(); + + CoverageTableFormat1 table = new CoverageTableFormat1 { CoverageFormat = format }; + + // USHORT GlyphCount + table.GlyphCount = _reader.ReadUInt16BigEndian(); + + // USHORT[] GlyphArray + table.GlyphArray = new ushort[table.GlyphCount]; + + for (int i = 0; i < table.GlyphCount; i++) + { + table.GlyphArray[i] = _reader.ReadUInt16BigEndian(); + } + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Serializer.cs new file mode 100644 index 0000000000..bc91b9601e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat1Serializer.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO +{ + internal class CoverageTableFormat1Serializer + { + public void Serialize(CoverageTableFormat1 table, FontsBinaryWriter writer) + { + // The table should only be serialized if it contains data + if (table.GlyphArray == null || table.GlyphArray.Length == 0) + { + // The caller (LigatureSubstSubTableSerializer) must handle the offset being 0. + return; + } + + // Must ensure the array is sorted ascendingly as required by the spec + // Since our CreateSubset already sorts by the new IDs, this should be safe. + ushort[] sortedGlyphArray = table.GlyphArray.OrderBy(g => g).ToArray(); + + // USHORT CoverageFormat (1) + writer.WriteUInt16BigEndian(1); + + // USHORT GlyphCount + writer.WriteUInt16BigEndian((ushort)sortedGlyphArray.Length); + + // USHORT[] GlyphArray + foreach (ushort gid in sortedGlyphArray) + { + writer.WriteUInt16BigEndian(gid); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Deserializer.cs new file mode 100644 index 0000000000..99c5a232b1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Deserializer.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO +{ + internal class CoverageTableFormat2Deserializer + { + private readonly FontsBinaryReader _reader; + + public CoverageTableFormat2Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public CoverageTableFormat2 Deserialize(long startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + + // Read Format (already known to be 2, but read to advance position) + ushort format = _reader.ReadUInt16BigEndian(); + + CoverageTableFormat2 table = new CoverageTableFormat2 { CoverageFormat = format }; + + // USHORT RangeCount + table.RangeCount = _reader.ReadUInt16BigEndian(); + + // Read RangeRecords + for (int i = 0; i < table.RangeCount; i++) + { + CoverageRangeRecord record = new CoverageRangeRecord + { + // USHORT StartGlyphID + StartGlyphID = _reader.ReadUInt16BigEndian(), + // USHORT EndGlyphID + EndGlyphID = _reader.ReadUInt16BigEndian(), + // USHORT StartCoverageIndex + StartCoverageIndex = _reader.ReadUInt16BigEndian() + }; + table.RangeRecords.Add(record); + } + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Serializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Serializer.cs new file mode 100644 index 0000000000..6998f67894 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Coverage/IO/CoverageTableFormat2Serializer.cs @@ -0,0 +1,54 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO +{ + internal class CoverageTableFormat2Serializer + { + public void Serialize(CoverageTableFormat2 table, FontsBinaryWriter writer) + { + if (table.RangeRecords == null || table.RangeRecords.Count == 0) + { + return; + } + + // Format 2 requires RangeRecords to be sorted by StartGlyphID + List sortedRecords = table.RangeRecords.OrderBy(r => r.StartGlyphID).ToList(); + + // USHORT CoverageFormat (2) + writer.WriteUInt16BigEndian(2); + + // USHORT RangeCount + writer.WriteUInt16BigEndian((ushort)sortedRecords.Count); + + // CoverageRangeRecord[] + // StartCoverageIndex MÅSTE vara 0, 1, 2, ... för de nya subsettabellerna. + ushort currentCoverageIndex = 0; + foreach (var record in sortedRecords) + { + // USHORT StartGlyphID + writer.WriteUInt16BigEndian(record.StartGlyphID); + // USHORT EndGlyphID + writer.WriteUInt16BigEndian(record.EndGlyphID); + // USHORT StartCoverageIndex (måste räknas om för subsetet) + writer.WriteUInt16BigEndian(currentCoverageIndex); + + // Räkna ut antalet glyfer i intervallet för nästa index + currentCoverageIndex += (ushort)(record.EndGlyphID - record.StartGlyphID + 1); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTable.cs new file mode 100644 index 0000000000..b19ed2e3e5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTable.cs @@ -0,0 +1,87 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Features +{ + /// + /// Represents the Feature List table in GSUB, mapping features to lookup indices. + /// + public class FeatureListTable : FontTableElement + { + /// + /// Gets or sets the list of feature records. + /// + public List FeatureRecords { get; set; } = new List(); + + internal override void Serialize(FontsBinaryWriter writer) + { + long startPos = writer.BaseStream.Position; + + // 1. Write FeatureCount + writer.WriteUInt16BigEndian((ushort)FeatureRecords.Count); + + // 2. Write FeatureRecords (Tag + Offset) + long offsetArrayStart = writer.BaseStream.Position; + foreach (var record in FeatureRecords) + { + writer.WriteTag(record.FeatureTag); + writer.WriteUInt16BigEndian(0); // Placeholder for offset + } + + // 3. Serialize FeatureTables and backfill offsets + for (int i = 0; i < FeatureRecords.Count; i++) + { + long currentPos = writer.BaseStream.Position; + long recordOffsetPos = offsetArrayStart + (i * 6) + 4; // Each record is 6 bytes (4 tag + 2 offset) + + // Update the offset in the header + this.WriteRelativeOffset(writer, startPos, recordOffsetPos); + + // Write the actual FeatureTable + FeatureRecords[i].FeatureTable.Serialize(writer); + } + } + + /// + /// Rewrites the feature list for a subset font. + /// + internal FeatureRewriteResult Rewrite(FontSubsettingContext context, Dictionary lookupMap) + { + var newFeatures = new List(); + var oldToNewFeatureMap = new Dictionary(); + + for (int oldIndex = 0; oldIndex < this.FeatureRecords.Count; oldIndex++) + { + var feature = this.FeatureRecords[oldIndex]; + + var rewrittenFeature = feature.Rewrite(context, lookupMap); + if (rewrittenFeature != null) + { + int newIndex = newFeatures.Count; + oldToNewFeatureMap[oldIndex] = newIndex; + newFeatures.Add(rewrittenFeature); + } + } + + return new FeatureRewriteResult + { + NewFeatureList = new FeatureListTable { FeatureRecords = newFeatures }, + OldToNewIndexMap = oldToNewFeatureMap + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTableLoader.cs new file mode 100644 index 0000000000..58fb92387b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureListTableLoader.cs @@ -0,0 +1,85 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB Shared FeatureList loader + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Features +{ + /// + /// Shared loader for FeatureListTable used by both GSUB and GPOS + /// + internal static class FeatureListTableLoader + { + public static FeatureListTable Load(FontsBinaryReader reader, long featureListStart) + { + var featureList = new FeatureListTable(); + ushort featureCount = reader.ReadUInt16BigEndian(); + + var featureOffsets = new List(); + for (int i = 0; i < featureCount; i++) + { + var tag = new Tag(reader); + ushort offset = reader.ReadUInt16BigEndian(); + featureOffsets.Add(new FeatureOffsetRecord { Tag = tag, Offset = offset }); + } + + long positionAfterRecords = reader.BaseStream.Position; + + // Load feature tables + foreach (var record in featureOffsets) + { + reader.BaseStream.Seek(featureListStart + record.Offset, SeekOrigin.Begin); + var featureTable = LoadFeatureTable(reader); + + featureList.FeatureRecords.Add(new FeatureRecord + { + FeatureTag = record.Tag, + FeatureOffset = record.Offset, + FeatureTable = featureTable + }); + } + + reader.BaseStream.Seek(positionAfterRecords, SeekOrigin.Begin); + return featureList; + } + + private static FeatureTable LoadFeatureTable(FontsBinaryReader reader) + { + var featureTable = new FeatureTable(); + featureTable.FeatureParams = reader.ReadUInt16BigEndian(); + featureTable.LookupCount = reader.ReadUInt16BigEndian(); + + if (featureTable.LookupCount > 0) + { + featureTable.LookupListIndices = new ushort[featureTable.LookupCount]; + for (int i = 0; i < featureTable.LookupCount; i++) + { + featureTable.LookupListIndices[i] = reader.ReadUInt16BigEndian(); + } + } + else + { + featureTable.LookupListIndices = new ushort[0]; + } + + return featureTable; + } + + // Helper struct for .NET 3.5 compatibility (no tuples) + private struct FeatureOffsetRecord + { + public Tag Tag; + public ushort Offset; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRecord.cs new file mode 100644 index 0000000000..15a9417122 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRecord.cs @@ -0,0 +1,66 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Features +{ + /// + /// Represents a Feature Record within a Feature List Table. + /// Associates a 4-byte feature tag with a specific Feature Table. + /// + public class FeatureRecord : FontTableElement + { + /// + /// Gets or sets the 4-byte feature identifier tag (e.g., 'liga', 'kern'). + /// + public Tag FeatureTag { get; set; } + + /// + /// Gets or sets the offset to the Feature Table, relative to the start of the Feature List Table. + /// + public ushort FeatureOffset { get; set; } + + /// + /// Gets or sets the actual Feature Table associated with this record. + /// + public FeatureTable FeatureTable { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + throw new NotImplementedException(); + } + + internal FeatureRecord Rewrite(FontSubsettingContext context, Dictionary lookupMap) + { + if (this.FeatureTable == null) return null; + + // Skapa en ny tabell baserat på den gamla + var rewrittenTable = this.FeatureTable.Rewrite(context, lookupMap); + + // Om tabellen inte längre pekar på några lookups, kastar vi hela recorden + if (rewrittenTable == null || rewrittenTable.LookupListIndices.Length == 0) + { + return null; + } + + return new FeatureRecord + { + FeatureTag = this.FeatureTag, + FeatureTable = rewrittenTable + // FeatureOffset räknas ut under serialiseringen senare + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRewriteResult.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRewriteResult.cs new file mode 100644 index 0000000000..26b7508f42 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureRewriteResult.cs @@ -0,0 +1,22 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Features +{ + internal class FeatureRewriteResult + { + public FeatureListTable NewFeatureList { get; set; } + public Dictionary OldToNewIndexMap { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureTable.cs new file mode 100644 index 0000000000..5e77038fdf --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Features/FeatureTable.cs @@ -0,0 +1,94 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Features +{ + /// + /// Represents a Feature Table which defines a specific font feature (e.g., ligatures) + /// by pointing to one or more lookups in the global Lookup List. + /// + public class FeatureTable : FontTableElement + { + /// + /// Gets or sets the offset to a feature parameters table. + /// Usually set to 0 unless the feature requires specific parameters (e.g., 'size'). + /// + public ushort FeatureParams { get; set; } + + /// + /// Gets or sets the number of lookups associated with this feature. + /// + public ushort LookupCount { get; set; } + + /// + /// Gets or sets an array of indices into the global LookupListTable. + /// These indices define which lookups are triggered when this feature is enabled. + /// + public ushort[] LookupListIndices { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + // 1. FeatureParams: Offset to parameters (Set to 0 per spec for most features) + writer.WriteUInt16BigEndian(this.FeatureParams); + + // 2. LookupCount: Number of lookups for this feature + if (this.LookupListIndices == null) + { + writer.WriteUInt16BigEndian(0); + } + else + { + writer.WriteUInt16BigEndian((ushort)this.LookupListIndices.Length); + } + + // 3. LookupListIndices: Array of indices into the LookupList + if (this.LookupListIndices != null) + { + foreach (ushort lookupIndex in this.LookupListIndices) + { + writer.WriteUInt16BigEndian(lookupIndex); + } + } + } + + internal FeatureTable Rewrite(FontSubsettingContext context, Dictionary lookupMap) + { + var newIndices = new List(); + + if (this.LookupListIndices != null) + { + foreach (var oldIndex in this.LookupListIndices) + { + // Kolla om den gamla lookupen finns kvar i vår nya, filtrerade lista + if (lookupMap.TryGetValue(oldIndex, out int newIndex)) + { + newIndices.Add((ushort)newIndex); + } + } + } + + // Om inga lookups finns kvar för denna feature, returnera null + // så att Recorden kan rensas bort. + if (newIndices.Count == 0) return null; + + return new FeatureTable + { + FeatureParams = this.FeatureParams, + LookupCount = (ushort)newIndices.Count, + LookupListIndices = newIndices.ToArray() + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/ExtensionSubTableBase.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/ExtensionSubTableBase.cs new file mode 100644 index 0000000000..f3d0e91aa5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/ExtensionSubTableBase.cs @@ -0,0 +1,62 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 12/21/2025 EPPlus Software AB Refactor: Common base for Extension + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups +{ + /// + /// Base class for Extension Substitution (Type 7) and Extension Positioning (Type 9). + /// Used to reference subtables that exceed the 16-bit offset limit. + /// + public abstract class ExtensionSubTableBase : FontTableElement + { + /// + /// Gets or sets the lookup type of the subtable pointed to by the extension. + /// For GSUB: 1-6 or 8. For GPOS: 1-8. + /// + public ushort ExtensionLookupType { get; set; } + + /// + /// Gets or sets the actual subtable being extended. + /// + public FontTableElement ExtendedSubTable { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + long startPos = writer.BaseStream.Position; + + // 1. Write Format (always 1) + writer.WriteUInt16BigEndian(1); + + // 2. Write the original Lookup Type + writer.WriteUInt16BigEndian(ExtensionLookupType); + + // 3. Write Placeholder for 32-bit Offset (ULONG) + long offsetPos = writer.BaseStream.Position; + writer.WriteUInt32BigEndian(0); + + // 4. Serialize the extended subtable + if (ExtendedSubTable != null) + { + long subTablePos = writer.BaseStream.Position; + uint relativeOffset = (uint)(subTablePos - startPos); + + // Go back and write the 32-bit offset + writer.BaseStream.Seek(offsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt32BigEndian(relativeOffset); + + // Return to end of subtable + writer.BaseStream.Seek(subTablePos, System.IO.SeekOrigin.Begin); + ExtendedSubTable.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupListTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupListTable.cs new file mode 100644 index 0000000000..8b57abd8a4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupListTable.cs @@ -0,0 +1,84 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using EPPlus.Fonts.OpenType.Subsetting; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups +{ + /// + /// Represents the Lookup List table in GSUB, which contains all the lookups used for substitutions. + /// + public class LookupListTable : FontTableElement + { + /// + /// Gets or sets the list of lookups. + /// + public List Lookups { get; set; } = new List(); + + internal override void Serialize(FontsBinaryWriter writer) + { + long startPos = writer.BaseStream.Position; + + // 1. Write LookupCount + writer.WriteUInt16BigEndian((ushort)Lookups.Count); + + // 2. Placeholders for LookupOffsets + long offsetArrayStart = writer.BaseStream.Position; + for (int i = 0; i < Lookups.Count; i++) + { + writer.WriteUInt16BigEndian(0); + } + + // 3. Serialize Lookups and backfill offsets + for (int i = 0; i < Lookups.Count; i++) + { + long currentPos = writer.BaseStream.Position; + long offsetInArray = offsetArrayStart + (i * 2); + + this.WriteRelativeOffset(writer, startPos, offsetInArray); + Lookups[i].Serialize(writer); + } + } + + /// + /// Rewrites the lookup list. Note that in a full implementation, + /// removing lookups might require remapping indexes in Features. + /// + internal LookupRewriteResult Rewrite(FontSubsettingContext context) + { + + var result = new LookupRewriteResult + { + NewLookupList = new LookupListTable(), + OldToNewIndexMap = new Dictionary() + }; + + for (int i = 0; i < this.Lookups.Count; i++) + { + var oldLookup = this.Lookups[i]; + + var rewrittenLookup = context.GsubProcessor.RewriteLookup(context, oldLookup); + + if (rewrittenLookup != null && rewrittenLookup.SubTables.Count > 0) + { + int newIndex = result.NewLookupList.Lookups.Count; + result.NewLookupList.Lookups.Add(rewrittenLookup); + result.OldToNewIndexMap[i] = newIndex; + + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupRewriteResult.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupRewriteResult.cs new file mode 100644 index 0000000000..96287bbf7c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupRewriteResult.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups +{ + internal class LookupRewriteResult + { + public LookupListTable NewLookupList { get; set; } + public Dictionary OldToNewIndexMap { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupTable.cs new file mode 100644 index 0000000000..39a9b64146 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Lookups/LookupTable.cs @@ -0,0 +1,111 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using EPPlus.Fonts.OpenType.Subsetting; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups +{ + /// + /// Represents a Lookup table in the GSUB table. + /// A lookup contains one or more subtables of the same type. + /// + [DebuggerDisplay("LookupType: {LookupType}, Subtable count: {SubTableCount}")] + public class LookupTable : FontTableElement + { + /// + /// The type of information this lookup provides (e.g., 1 for Single, 4 for Ligature). + /// + public ushort LookupType { get; set; } + + /// + /// Flags that specify how to process the lookup (e.g., IgnoreMarks, RightToLeft). + /// + public ushort LookupFlag { get; set; } + + /// + /// Gets or sets the number of subtables. + /// Note: When serializing or rewriting, SubTables.Count is used. + /// + public ushort SubTableCount { get; set; } + + /// + /// A list of subtables containing the actual substitution data. + /// + public List SubTables { get; set; } = new List(); + + /// + /// Optional MarkFilteringSet index in the GDEF table. + /// + public ushort MarkFilteringSet { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + long lookupStart = writer.BaseStream.Position; + + // 1. Write LookupType + writer.WriteUInt16BigEndian(LookupType); + + // 2. Write LookupFlag + writer.WriteUInt16BigEndian(LookupFlag); + + // 3. Write SubTableCount + writer.WriteUInt16BigEndian((ushort)SubTables.Count); + + // 4. Placeholders for SubTable offsets + long offsetArrayStart = writer.BaseStream.Position; + for (int i = 0; i < SubTables.Count; i++) + { + writer.WriteUInt16BigEndian(0); + } + + // 5. If UseMarkFilteringSet flag is set (0x0010), write MarkFilteringSet + if ((LookupFlag & 0x0010) != 0) + { + writer.WriteUInt16BigEndian(MarkFilteringSet); + } + + // --- Serialize SubTables and backfill offsets --- + for (int i = 0; i < SubTables.Count; i++) + { + long currentPos = writer.BaseStream.Position; + long offsetInArray = offsetArrayStart + (i * 2); + + // Update the offset in the header + this.WriteRelativeOffset(writer, lookupStart, offsetInArray); + + // Write the subtable data + SubTables[i].Serialize(writer); + } + } + + /// + /// Creates a new LookupTable containing only the substitutions relevant to the subset. + /// + internal LookupTable Rewrite(FontSubsettingContext context) + { + // Istället för att gissa här, fråga processorn efter rätt handler! + // (Vi antar att context har tillgång till din GsubProcessor) + var handler = context.GsubProcessor.GetHandler(this.LookupType); + + if (handler != null) + { + return handler.Rewrite(context, this); + } + + // Fallback: Om ingen handler finns, gör som förut eller returnera null + return null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysRecord.cs new file mode 100644 index 0000000000..e0b54feafc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysRecord.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + /// + /// Represents a Language System Record, which associates a specific language tag + /// with a Language System Table. + /// + public class LangSysRecord + { + /// + /// Gets or sets the 4-byte Language System tag (e.g., 'SVE ' for Swedish), stored as a uint. + /// + public uint LangSysTag { get; set; } + + /// + /// Gets or sets the actual Language System Table associated with this record. + /// + public LangSysTable LangSysTable { get; set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysTable.cs new file mode 100644 index 0000000000..50e5b5a9fc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/LangSysTable.cs @@ -0,0 +1,65 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + /// + /// Represents a Language System Table, which defines the features available + /// for a particular language system within a script. + /// + public class LangSysTable : FontTableElement + { + /// + /// Gets or sets the lookup order. Reserved for future use; currently set to 0. + /// + public ushort LookupOrder { get; set; } + + /// + /// Gets or sets the index of a required feature in the FeatureList. + /// Set to 0xFFFF if no required feature is defined. + /// + public ushort RequiredFeatureIndex { get; set; } + + /// + /// Gets or sets the number of optional features associated with this language system. + /// + public ushort FeatureIndexCount { get; set; } + + /// + /// Gets or sets an array of indices into the FeatureList for the optional features. + /// + public ushort[] FeatureIndices { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + // 1. LookupOrder: Reserved, should be 0 + writer.WriteUInt16BigEndian(this.LookupOrder); + + // 2. RequiredFeatureIndex: Index into FeatureList or 0xFFFF + writer.WriteUInt16BigEndian(this.RequiredFeatureIndex); + + // 3. FeatureIndexCount: Number of optional features + ushort count = this.FeatureIndices != null ? (ushort)this.FeatureIndices.Length : (ushort)0; + writer.WriteUInt16BigEndian(count); + + // 4. FeatureIndices: Array of indices into the FeatureList + if (this.FeatureIndices != null) + { + foreach (ushort index in this.FeatureIndices) + { + writer.WriteUInt16BigEndian(index); + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTable.cs new file mode 100644 index 0000000000..8c95b8bf7d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTable.cs @@ -0,0 +1,170 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + /// + /// Represents the Script List table in an OpenType font. + /// It identifies the scripts in the font and points to the Script tables that define language systems. + /// + public class ScriptListTable : FontTableElement + { + /// + /// Gets or sets the list of Script Records. + /// + public List ScriptRecords { get; set; } = new List(); + + internal override void Serialize(FontsBinaryWriter writer) + { + // Store the start position of the ScriptList for relative offset calculations + long scriptListStartOffset = writer.BaseStream.Position; + + // 1. Write ScriptCount (USHORT) + writer.WriteUInt16BigEndian((ushort)this.ScriptRecords.Count); + + // 2. Write ScriptRecords (Tag + Placeholder for Offset) + List recordOffsetPositions = new List(); + + foreach (var record in this.ScriptRecords) + { + // Write ScriptTag (4 bytes) + writer.Write(record.ScriptTag.ToBytes()); + + // Store position for the ScriptTableOffset (2 bytes) placeholder + recordOffsetPositions.Add(writer.BaseStream.Position); + writer.WriteUInt16BigEndian(0); + } + + // --- Serialize ScriptTables --- + + // We iterate through the records and serialize the associated ScriptTable for each. + for (int i = 0; i < this.ScriptRecords.Count; i++) + { + var record = this.ScriptRecords[i]; + long currentOffset = writer.BaseStream.Position; + + // Calculate the offset relative to the start of the ScriptListTable + ushort relativeScriptTableOffset = (ushort)(currentOffset - scriptListStartOffset); + + // 1. Return to the record's offset field and backfill the calculated value + long recordOffsetPos = recordOffsetPositions[i]; + writer.BaseStream.Seek(recordOffsetPos, SeekOrigin.Begin); + writer.WriteUInt16BigEndian(relativeScriptTableOffset); + + // 2. Restore the stream position to continue serializing data + writer.BaseStream.Seek(currentOffset, SeekOrigin.Begin); + + // Serialize the ScriptTable itself (must implement Serialize) + if (record.ScriptTable != null) + { + record.ScriptTable.Serialize(writer); + } + } + } + + internal ScriptListTable Rewrite(FontSubsettingContext context, Dictionary featureIndexMap) + { + var newScriptList = new ScriptListTable(); + + foreach (var scriptRecord in this.ScriptRecords) + { + var newScriptRecord = new ScriptRecord + { + ScriptTag = scriptRecord.ScriptTag, + ScriptTable = RewriteScriptTable(scriptRecord.ScriptTable, featureIndexMap) + }; + + newScriptList.ScriptRecords.Add(newScriptRecord); + } + + return newScriptList; + } + + /// + /// Rewrites a ScriptTable by remapping feature indices. + /// + private ScriptTable RewriteScriptTable(ScriptTable original, Dictionary featureIndexMap) + { + var newScriptTable = new ScriptTable + { + DefaultLangSysOffset = original.DefaultLangSysOffset + }; + + // Rewrite DefaultLangSys + if (original.DefaultLangSys != null) + { + newScriptTable.DefaultLangSys = RewriteLangSys(original.DefaultLangSys, featureIndexMap); + } + + // Rewrite LangSysRecords + foreach (var langSysRecord in original.LangSysRecords) + { + var newLangSys = RewriteLangSys(langSysRecord.LangSysTable, featureIndexMap); + if (newLangSys != null && newLangSys.FeatureIndices.Length > 0) + { + newScriptTable.LangSysRecords.Add(new LangSysRecord + { + LangSysTag = langSysRecord.LangSysTag, + LangSysTable = newLangSys + }); + } + } + + return newScriptTable; + } + + /// + /// Rewrites a LangSysTable by remapping feature indices. + /// + private LangSysTable RewriteLangSys(LangSysTable original, Dictionary featureIndexMap) + { + if (original == null) + return null; + + var newFeatureIndices = new List(); + + // Remap each feature index + foreach (var oldIndex in original.FeatureIndices) + { + if (featureIndexMap.TryGetValue(oldIndex, out int newIndex)) + { + newFeatureIndices.Add((ushort)newIndex); + } + // Else: feature was removed, skip it + } + + // Handle RequiredFeatureIndex + ushort newRequiredFeatureIndex = 0xFFFF; // Default: no required feature + if (original.RequiredFeatureIndex != 0xFFFF) + { + if (featureIndexMap.TryGetValue(original.RequiredFeatureIndex, out int mappedRequired)) + { + newRequiredFeatureIndex = (ushort)mappedRequired; + } + // Else: required feature was removed, set to 0xFFFF + } + + return new LangSysTable + { + LookupOrder = original.LookupOrder, + RequiredFeatureIndex = newRequiredFeatureIndex, + FeatureIndexCount = (ushort)newFeatureIndices.Count, + FeatureIndices = newFeatureIndices.ToArray() + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTableLoader.cs new file mode 100644 index 0000000000..5f03248ef6 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptListTableLoader.cs @@ -0,0 +1,120 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB Shared ScriptList loader + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gsub.Data; +using EPPlus.Fonts.OpenType.Tables.Gsub.IO; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + /// + /// Shared loader for ScriptListTable used by both GSUB and GPOS + /// + internal static class ScriptListTableLoader + { + public static ScriptListTable Load(FontsBinaryReader reader, long scriptListStart) + { + var scriptList = new ScriptListTable(); + + ushort scriptCount = reader.ReadUInt16BigEndian(); + + // Read script records + var scriptOffsets = new List(); + for (int i = 0; i < scriptCount; i++) + { + var tag = new Tag(reader); + ushort offset = reader.ReadUInt16BigEndian(); + scriptOffsets.Add(new ScriptOffsetRecord { Tag = tag, Offset = offset }); + } + + long positionAfterRecords = reader.BaseStream.Position; + + // Load script tables + foreach (var record in scriptOffsets) + { + // ✅ Seek to script table position + reader.BaseStream.Seek(scriptListStart + record.Offset, SeekOrigin.Begin); + + // ✅ LoadScriptTable reads from current position + var scriptTable = LoadScriptTable(reader); + + scriptList.ScriptRecords.Add(new ScriptRecord + { + ScriptTag = record.Tag, + ScriptOffset = record.Offset, + ScriptTable = scriptTable + }); + } + + reader.BaseStream.Seek(positionAfterRecords, SeekOrigin.Begin); + return scriptList; + } + + private static ScriptTable LoadScriptTable(FontsBinaryReader reader) + { + long scriptTableStart = reader.BaseStream.Position; + + var scriptTable = new ScriptTable(); + ushort defaultLangSysOffset = reader.ReadUInt16BigEndian(); + scriptTable.DefaultLangSysOffset = defaultLangSysOffset; + ushort langSysCount = reader.ReadUInt16BigEndian(); + + var recordsToLoad = new Dictionary(); + for (int i = 0; i < langSysCount; i++) + { + uint langSysTag = reader.ReadUInt32BigEndian(); + ushort langSysOffset = reader.ReadUInt16BigEndian(); + + if (!recordsToLoad.ContainsKey(langSysTag)) + { + recordsToLoad.Add(langSysTag, langSysOffset); + } + } + + long positionAfterRecords = reader.BaseStream.Position; + var langSysDeserializer = new LangSysTableDeserializer(reader); + + // Load default LangSys + if (defaultLangSysOffset > 0) + { + long langSysAbsoluteStart = scriptTableStart + defaultLangSysOffset; + scriptTable.DefaultLangSys = langSysDeserializer.Deserialize(langSysAbsoluteStart); + } + + // Load other LangSys records + foreach (var kvp in recordsToLoad) + { + long langSysAbsoluteStart = scriptTableStart + kvp.Value; + + var langSysTable = langSysDeserializer.Deserialize(langSysAbsoluteStart); + + scriptTable.LangSysRecords.Add(new LangSysRecord + { + LangSysTag = kvp.Key, + LangSysTable = langSysTable + }); + } + + reader.BaseStream.Seek(positionAfterRecords, SeekOrigin.Begin); + + return scriptTable; + } + + // Helper struct for .NET 3.5 compatibility (no tuples) + private struct ScriptOffsetRecord + { + public Tag Tag; + public ushort Offset; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptRecord.cs new file mode 100644 index 0000000000..984ac7c9fa --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptRecord.cs @@ -0,0 +1,52 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + /// + /// Represents a Script Record within the Script List table. + /// Each record associates a unique 4-byte script tag with an offset to a Script Table. + /// + public class ScriptRecord : FontTableElement + { + /// + /// Gets or sets the 4-byte identifier for the script (e.g., 'latn' for Latin). + /// + public Tag ScriptTag { get; set; } + + /// + /// Gets or sets the offset to the Script Table, relative to the start of the ScriptList table. + /// + public ushort ScriptOffset { get; set; } + + /// + /// Gets or sets the actual Script Table associated with this record. + /// + public ScriptTable ScriptTable { get; set; } + + /// + /// Serializes the Script Record. + /// Note: In most implementations, the ScriptListTable handles the serialization of + /// these records to manage the offset backfilling correctly. + /// + /// The binary writer. + internal override void Serialize(FontsBinaryWriter writer) + { + // The ScriptListTable typically handles this to manage relative offsets. + // If called directly, it writes the tag and the current ScriptOffset value. + writer.Write(this.ScriptTag.ToBytes()); + writer.WriteUInt16BigEndian(this.ScriptOffset); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptTable.cs new file mode 100644 index 0000000000..20d3c7eefe --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Common/Layout/Scripts/ScriptTable.cs @@ -0,0 +1,108 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts +{ + public class ScriptTable : FontTableElement + { + // Property is kept mainly for deserialization purposes, its value is calculated during serialization. + public ushort DefaultLangSysOffset { get; set; } + + /// + /// Contains the deserialized LangSysTable object for the default language system. + /// Checked for null status during serialization. + /// + public LangSysTable DefaultLangSys { get; set; } + + /// + /// Contains records for all language systems supported by this script (excluding the default one). + /// + public List LangSysRecords { get; set; } = new List(); + + internal override void Serialize(FontsBinaryWriter writer) + { + // The writer's current position is the start of the ScriptTable. + long scriptTableStartOffset = writer.BaseStream.Position; + + // 1. USHORT DefaultLangSysOffset (Placeholder) + long defaultLangSysOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); + + // 2. USHORT LangSysCount + writer.WriteUInt16BigEndian((ushort)this.LangSysRecords.Count); + + // 3. LangSysRecord[] - Write tags and placeholders for LangSysOffset + List langSysOffsetPositions = new List(); + + foreach (var record in this.LangSysRecords) + { + // Write LangSysTag (4 bytes) + writer.WriteUInt32BigEndian(record.LangSysTag); + + // Placeholder for LangSysOffset (2 bytes) + langSysOffsetPositions.Add(writer.BaseStream.Position); + writer.WriteUInt16BigEndian(0); + } + + // --- Serialize LangSysTable(s) --- + + // 1. Serialize DefaultLangSysTable + if (this.DefaultLangSys != null) + { + long currentOffset = writer.BaseStream.Position; + + // Calculate DefaultLangSys offset: LangSys start - ScriptTable start + ushort relativeOffset = (ushort)(currentOffset - scriptTableStartOffset); + + // Save current position + long positionBeforeSeek = writer.BaseStream.Position; + + // Fill in placeholder + writer.BaseStream.Seek(defaultLangSysOffsetPos, SeekOrigin.Begin); + writer.WriteUInt16BigEndian(relativeOffset); + + // Restore position + writer.BaseStream.Seek(positionBeforeSeek, SeekOrigin.Begin); + + // Serialize DefaultLangSysTable + this.DefaultLangSys.Serialize(writer); + } + + // 2. Serialize other LangSysTables from LangSysRecords + int recordIndex = 0; + foreach (var record in this.LangSysRecords) + { + long currentOffset = writer.BaseStream.Position; + + // Calculate offset: LangSysTable start - ScriptTable start + ushort relativeOffset = (ushort)(currentOffset - scriptTableStartOffset); + + // Fill in placeholder for LangSysRecord + long recordOffsetPos = langSysOffsetPositions[recordIndex]; + + // Save current position + long positionBeforeSeek = writer.BaseStream.Position; + + writer.BaseStream.Seek(recordOffsetPos, SeekOrigin.Begin); + writer.WriteUInt16BigEndian(relativeOffset); + writer.BaseStream.Seek(positionBeforeSeek, SeekOrigin.Begin); // Restore position + + // Serialize LangSysTable + record.LangSysTable.Serialize(writer); + recordIndex++; + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Fixed16Dot16.cs b/src/EPPlus.Fonts.OpenType/Tables/Fixed16Dot16.cs new file mode 100644 index 0000000000..76d2a53173 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Fixed16Dot16.cs @@ -0,0 +1,60 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables +{ + public class Fixed16Dot16 : FontTableElement + { + public Fixed16Dot16(int rawValue) + { + RawValue = rawValue; + FloatValue = rawValue / 65536f; + } + + public Fixed16Dot16(float floatValue) + { + FloatValue = floatValue; + RawValue = (int)(floatValue * 65536f); + } + + /// + /// The raw value in 16.16 fixed-point-format (signed 32-bit integer) + /// + public int RawValue { get; } + + /// + /// The value as a float (ex. -12.5, 0.0, 1.25) + /// + public float FloatValue { get; } + + public override string ToString() + { + return FloatValue.ToString("0.####", System.Globalization.CultureInfo.InvariantCulture); + } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteInt32BigEndian(RawValue); + } + + internal static Fixed16Dot16 ReadFrom(FontsBinaryReader reader) + { + int raw = reader.ReadInt32BigEndian(); + return new Fixed16Dot16(raw); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/FontTableBase.cs b/src/EPPlus.Fonts.OpenType/Tables/FontTableBase.cs new file mode 100644 index 0000000000..b77eeb9f7b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/FontTableBase.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables +{ + public abstract class FontTableBase + { + internal byte[] Serialize(OpenTypeFont font) + { + return Serialize(font.GetSerializationContext()); + } + + internal byte[] Serialize(FontSerializationContext context) + { + using var ms = new MemoryStream(); + using var writer = new FontsBinaryWriter(ms); + SerializeInternal(writer, context); + return ms.ToArray(); + } + + internal void Serialize(FontsBinaryWriter writer, FontSerializationContext context) + { + SerializeInternal(writer, context); + } + internal abstract void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context); + + internal abstract void Clear(); + + public int GetLength(OpenTypeFont font) + { + return Serialize(font.GetSerializationContext()).Length; + } + + public int GetLength(FontSerializationContext context) + { + return Serialize(context).Length; + } + + public abstract string Name { get; } + + public abstract bool IsEssentialTable { get; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/FontTableElement.cs b/src/EPPlus.Fonts.OpenType/Tables/FontTableElement.cs new file mode 100644 index 0000000000..ac020ac11c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/FontTableElement.cs @@ -0,0 +1,42 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables +{ + public abstract class FontTableElement + { + internal byte[] Serialize() + { + using var ms = new MemoryStream(); + using var writer = new FontsBinaryWriter(ms); + Serialize(writer); + return ms.ToArray(); + } + + internal abstract void Serialize(FontsBinaryWriter writer); + + internal void WriteRelativeOffset(FontsBinaryWriter writer, long startOfTable, long positionToUpdate) + { + long currentPos = writer.BaseStream.Position; + + // Beräkna offset (måste rymmas i en USHORT per OpenType spec) + ushort relativeOffset = (ushort)(currentPos - startOfTable); + + // Gå tillbaka, skriv, och återställ position + writer.BaseStream.Seek(positionToUpdate, SeekOrigin.Begin); + writer.WriteUInt16BigEndian(relativeOffset); + writer.BaseStream.Seek(currentPos, SeekOrigin.Begin); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyph.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyph.cs new file mode 100644 index 0000000000..9e4c019b14 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyph.cs @@ -0,0 +1,39 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + public class CompositeGlyph : FontTableElement + { + public List Components { get; set; } = new List(); + public byte[] Instructions { get; set; } = new byte[0]; + + internal override void Serialize(FontsBinaryWriter writer) + { + foreach (var component in Components) + { + component.Serialize(writer); + } + + if ((Components.Last().Flags & CompositeGlyphFlags.WE_HAVE_INSTRUCTIONS) != 0) + { + writer.WriteUInt16BigEndian((ushort)Instructions.Length); + writer.Write(Instructions); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyphFlags.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyphFlags.cs new file mode 100644 index 0000000000..32c5ac5d00 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/CompositeGlyphFlags.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + + [Flags] + public enum CompositeGlyphFlags : ushort + { + ARG_1_AND_2_ARE_WORDS = 0x0001, + ARGS_ARE_XY_VALUES = 0x0002, + ROUND_XY_TO_GRID = 0x0004, + WE_HAVE_A_SCALE = 0x0008, + MORE_COMPONENTS = 0x0020, + WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, + WE_HAVE_A_TWO_BY_TWO = 0x0080, + WE_HAVE_INSTRUCTIONS = 0x0100, + USE_MY_METRICS = 0x0200, + OVERLAP_COMPOUND = 0x0400, + SCALED_COMPONENT_OFFSET = 0x0800, + UNSCALED_COMPONENT_OFFSET = 0x1000 + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/FlagRun.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/FlagRun.cs new file mode 100644 index 0000000000..d54bda6339 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/FlagRun.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + + public class FlagRun + { + internal FlagRun() + { + + } + public byte Flag { get; set; } + public byte RepeatCount { get; set; } // 0 = no repeat + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTable.cs new file mode 100644 index 0000000000..12edeee2ed --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTable.cs @@ -0,0 +1,175 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tables.Post; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using static System.Net.Mime.MediaTypeNames; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + /// + /// This table contains information that describes the glyphs in the font in the TrueType outline format + /// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf + /// + public class GlyfTable : FontTableBase + { + internal GlyfTable(TableLoaderSettings settings) + { + _tableLoaderSettings = settings; + } + + internal GlyfTable(List glyphs) + { + Glyphs = glyphs ?? new List(); + } + + private readonly TableLoaderSettings _tableLoaderSettings; + + public override string Name => TableNames.Glyf; + + public override bool IsEssentialTable => true; + + /// + /// All glyphs in the font, indexed by glyph ID. + /// + public List Glyphs { get; set; } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + if (Glyphs == null || Glyphs.Count == 0) + return; + + if (_tableLoaderSettings != null) + { + // Originalfont: use locaOffsets from loader + var locaOffsets = TableLoaders.GetLocaTableLoader(_tableLoaderSettings).Load().Offsets; + for (int i = 0; i < Glyphs.Count; i++) + { + long glyphStart = writer.BaseStream.Position; + Glyph glyph = Glyphs[i]; + + if (glyph != null) + glyph.Serialize(writer); + + long glyphEnd = writer.BaseStream.Position; + int writtenLength = (int)(glyphEnd - glyphStart); + + if (i + 1 < locaOffsets.Count) + { + int expectedLength = (int)(locaOffsets[i + 1] - locaOffsets[i]); + if (expectedLength > writtenLength) + { + int padding = expectedLength - writtenLength; + for (int p = 0; p < padding; p++) + writer.Write((byte)0); + } + } + } + } + else + { + // Subset-font: align every glyph to 4 bytes + foreach (var glyph in Glyphs) + { + long start = writer.BaseStream.Position; + glyph.Serialize(writer); + long end = writer.BaseStream.Position; + + int writtenLength = (int)(end - start); + int padding = (4 - (writtenLength % 4)) % 4; + for (int p = 0; p < padding; p++) + writer.Write((byte)0); + } + } + } + + internal override void Clear() + { + Glyphs.Clear(); + } + + public Glyph GetGlyph(ushort glyphId) + { + if (Glyphs == null || glyphId >= Glyphs.Count) + return null; + + return Glyphs[glyphId]; + } + + + /// + /// Recursively adds all component glyph IDs used by composite glyphs in the given set. + /// Uses GetGlyph() to ensure lazy-loaded glyphs are properly resolved. + /// Critical for correct subsetting of fonts with composite glyphs (å, ä, ö, fi, fl, etc.). + /// + /// Set of glyph IDs to expand with component dependencies + public void ResolveCompositeGlyphs(HashSet glyphSet) + { + if (glyphSet == null) throw new ArgumentNullException("glyphSet"); + + bool addedNew; + do + { + addedNew = false; + ushort[] currentGlyphs = new List(glyphSet).ToArray(); // Snapshot for iteration + + foreach (ushort gid in currentGlyphs) + { + Glyph glyph = this.GetGlyph(gid); + if (glyph != null && + glyph.Header.numberOfContours < 0 && + glyph.CompositeData != null) + { + foreach (GlyphComponent component in glyph.CompositeData.Components) + { + if (glyphSet.Add(component.GlyphIndex)) + { + addedNew = true; + } + } + } + } + } while (addedNew); + } + + public string GetGlyphName(ushort glyphId, OpenTypeFont font) + { + // 1. Försök hämta från 'post' table (Format 2.0 – namnarray) + if (font.PostTable is PostTable post && post.version.Major == 2 && post.version.Minor == 0 && post.glyphNameIndex != null) + { + if (glyphId < post.glyphNameIndex.Count) + { + ushort nameIndex = post.glyphNameIndex[glyphId]; + + // nameIndex 0–257 = standard Macintosh names + if (nameIndex <= 257) + { + return StandardMacGlyphNames.NameFromIndex(nameIndex); + } + + // nameIndex > 257 = custom name in string data + if (nameIndex - 258 < post.glyphNameIndex?.Count) + { + return post.glyphNames[nameIndex - 258]; + } + } + } + + // 3. Sista utvägen: returnera "gidXXXXX" + return $"gid{glyphId}"; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableLoader.cs new file mode 100644 index 0000000000..3d3e1b9c2c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableLoader.cs @@ -0,0 +1,57 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + + +using EPPlus.Fonts.OpenType.Tables.Glyph.Serialization; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + internal class GlyfTableLoader : TableLoader + { + private readonly uint[] _glyphOffsets; + private readonly BoundingRectangle _emptyGlyph; + + public GlyfTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Glyf) + { + _glyphOffsets = TableLoaders.GetLocaTableLoader(settings).Load().Offsets.ToArray(); + _emptyGlyph = TableLoaders.GetHeadTableLoader(settings).Load().GetDefaultBounds(); + _settings = settings; + } + + + private readonly TableLoaderSettings _settings; + + protected override GlyfTable LoadInternal() + { + var glyphs = new Glyph[_glyphOffsets.Length]; + _reader.SetContext("glyf"); + for (int i = 0; i < _glyphOffsets.Length - 1; i++) + { + var start = _glyphOffsets[i]; + var end = _glyphOffsets[i + 1]; + + if (start == end) + { + continue; + } + + _reader.BaseStream.Position = _offset + start; + glyphs[i] = GlyphDeserializer.Deserialize(_reader); + } + _reader.SetContext(string.Empty); + return new GlyfTable(_settings) { Glyphs = new List(glyphs) }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableValidator.cs new file mode 100644 index 0000000000..18203a3de8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyfTableValidator.cs @@ -0,0 +1,238 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + + internal class GlyfTableValidator : TableValidatorBase + { + public override Type TableType => typeof(GlyfTable); + public override string TableName => TableNames.Glyf; + + public override TableValidationResult Validate(GlyfTable table, FontValidationContext context) + { + var result = new TableValidationResult { TableName = TableName, LogLevel = base.LogLevel }; + + // 1. Validate dependencies + var loca = context.Font.LocaTable; + var maxp = context.Font.MaxpTable; + + if (loca == null) + result.AddMessage(FontValidationSeverity.Error, "Missing loca table required by glyf."); + if (maxp == null) + result.AddMessage(FontValidationSeverity.Error, "Missing maxp table required by glyf."); + + if (maxp != null) + { + if (table.Glyphs.Count < maxp.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph count ({table.Glyphs.Count}) is less than maxp.numGlyphs ({maxp.numGlyphs}). Font may be broken."); + } + else if (table.Glyphs.Count > maxp.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Information, + $"Glyph count ({table.Glyphs.Count}) is greater than maxp.numGlyphs ({maxp.numGlyphs}). This is allowed but unusual."); + } + } + + if (loca != null && maxp != null) + { + if (loca.Offsets.Count < maxp.numGlyphs + 1) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca offsets count ({loca.Offsets.Count}) is less than maxp.numGlyphs + 1 ({maxp.numGlyphs + 1}). Font may be broken."); + } + else if (loca.Offsets.Count != table.Glyphs.Count + 1) + { + result.AddMessage(FontValidationSeverity.Information, + $"Loca offsets count ({loca.Offsets.Count}) does not match glyph count + 1 ({table.Glyphs.Count + 1}). This is allowed but unusual."); + } + } + + // 2. Validate glyphs + for (int i = 0; i < table.Glyphs.Count; i++) + { + var glyph = table.Glyphs[i]; + + // Check for empty/null glyphs using loca offsets + if (glyph == null) + { + if (loca != null && i + 1 < loca.Offsets.Count) + { + var lengthInLoca = loca.Offsets[i + 1] - loca.Offsets[i]; + if (lengthInLoca == 0) + { + // This is a legitimate empty glyph (like 'space') + result.AddMessage(FontValidationSeverity.Information, + $"Glyph {i} is empty (null) as confirmed by zero-length entry in loca table."); + } + else + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph {i} is null, but loca offsets indicate it should contain {lengthInLoca} bytes of data."); + } + } + else + { + result.AddMessage(FontValidationSeverity.Warning, + $"Glyph {i} is null and cannot be verified against loca table."); + } + continue; + } + + var header = glyph.Header; + if (header.xMin > header.xMax || header.yMin > header.yMax) + result.AddMessage(FontValidationSeverity.Error, $"Glyph {i} has invalid bounding box."); + + if (header.numberOfContours > 0) + { + if (glyph.SimpleData == null) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {i} is simple but has no SimpleData."); + } + else + { + ValidateSimpleGlyph(glyph.SimpleData, i, result); + } + } + else if (header.numberOfContours < 0) + { + if (glyph.CompositeData == null) + result.AddMessage(FontValidationSeverity.Error, $"Glyph {i} is composite but has no CompositeData."); + else + ValidateCompositeGlyph(glyph.CompositeData, i, result, table.Glyphs.Count); + } + else + { + // numberOfContours == 0: perfectly valid for whitespace + if (glyph.SimpleData != null || glyph.CompositeData != null) + result.AddMessage(FontValidationSeverity.Warning, $"Glyph {i} has contour count 0 but contains attached data objects."); + } + + // Validate actual serialized size vs loca table + if (loca != null && i + 1 < loca.Offsets.Count) + { + int actualSize = glyph.GetSize(); + uint expectedSize = loca.Offsets[i + 1] - loca.Offsets[i]; + + if (actualSize > expectedSize) + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph {i} serialized size ({actualSize}) exceeds space allocated in loca table ({expectedSize})."); + } + else if (actualSize < expectedSize) + { + // This is usually fine (padding), but good to log as info + result.AddMessage(FontValidationSeverity.Information, + $"Glyph {i} size ({actualSize}) is smaller than loca range ({expectedSize}). Padding: {expectedSize - actualSize} bytes."); + } + } + } + + return result; + } + + private void ValidateSimpleGlyph(SimpleGlyph simple, int glyphIndex, TableValidationResult result) + { + if (simple.EndPtsOfContours == null || simple.EndPtsOfContours.Length == 0) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} has no EndPtsOfContours."); + return; + } + + int actualPointCount = simple.Points?.Count ?? 0; + bool hasBinaryData = (simple.XBytes != null && simple.XBytes.Length > 0) || + (simple.YBytes != null && simple.YBytes.Length > 0); + + if (actualPointCount == 0 && !hasBinaryData) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Glyph {glyphIndex} has EndPtsOfContours but no point list or binary coordinate data loaded."); + } + else if (actualPointCount > 0) + { + // Full consistency check for decoded points + if (simple.EndPtsOfContours.Last() != actualPointCount - 1) + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph {glyphIndex} EndPtsOfContours last index ({simple.EndPtsOfContours.Last()}) " + + $"mismatch with point count ({actualPointCount})."); + } + + short minX = simple.Points.Min(p => p.X); + short maxX = simple.Points.Max(p => p.X); + short minY = simple.Points.Min(p => p.Y); + short maxY = simple.Points.Max(p => p.Y); + + if (minX < -32768 || maxX > 32767 || minY < -32768 || maxY > 32767) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} coordinates out of 16-bit range."); + } + + if (simple.Flags != null && simple.Flags.Count != actualPointCount) + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph {glyphIndex} has {simple.Flags.Count} flags but {actualPointCount} points."); + } + } + + if (simple.Instructions != null && simple.Instructions.Length > 65535) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} instruction length exceeds 65535."); + } + } + + private void ValidateCompositeGlyph(CompositeGlyph composite, int glyphIndex, TableValidationResult result, int glyphCount) + { + if (composite.Components == null || composite.Components.Count == 0) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} is composite but has no components."); + return; + } + + for (int c = 0; c < composite.Components.Count; c++) + { + var comp = composite.Components[c]; + if (comp.GlyphIndex >= glyphCount) + { + result.AddMessage(FontValidationSeverity.Error, + $"Glyph {glyphIndex} component {c} references invalid GID {comp.GlyphIndex}."); + } + + // Flag validation + bool hasScale = (comp.Flags & CompositeGlyphFlags.WE_HAVE_A_SCALE) != 0; + bool hasXYScale = (comp.Flags & CompositeGlyphFlags.WE_HAVE_AN_X_AND_Y_SCALE) != 0; + bool hasTwoByTwo = (comp.Flags & CompositeGlyphFlags.WE_HAVE_A_TWO_BY_TWO) != 0; + + if ((hasScale ? 1 : 0) + (hasXYScale ? 1 : 0) + (hasTwoByTwo ? 1 : 0) > 1) + { + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} component {c} has conflicting scale flags."); + } + } + + var lastComp = composite.Components.Last(); + if ((lastComp.Flags & CompositeGlyphFlags.WE_HAVE_INSTRUCTIONS) != 0) + { + if (composite.Instructions == null || composite.Instructions.Length == 0) + result.AddMessage(FontValidationSeverity.Error, $"Glyph {glyphIndex} missing instructions despite flag."); + } + } + + private bool IsF2Dot14Valid(short value) => value >= -16384 && value <= 16384; + private bool IsF2Dot14Safe(short value) => value >= short.MinValue && value <= short.MaxValue; + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/Glyph.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Glyph.cs new file mode 100644 index 0000000000..8ac61725cc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Glyph.cs @@ -0,0 +1,61 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + public class Glyph : FontTableElement + { + public GlyphHeader Header { get; internal set; } + + public SimpleGlyph SimpleData { get; internal set; } + + public CompositeGlyph CompositeData { get; internal set; } + + + public int GetSize() + { + using (var ms = new MemoryStream()) + using (var writer = new FontsBinaryWriter(ms)) + { + Serialize(writer); + return (int)ms.Length; + } + } + + + internal override void Serialize(FontsBinaryWriter writer) + { + if (Header.numberOfContours == 0 && SimpleData == null && CompositeData == null) + { + return; // Don't write anything for empty glyphs! + } + Header.Serialize(writer); + + if (Header.numberOfContours > 0 && SimpleData != null) + { + SimpleData.Serialize(writer); + } + else if (Header.numberOfContours < 0 && CompositeData != null) + { + CompositeData.Serialize(writer); + } + // If numberOfContours == 0 → empty glyph, only header + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphComponent.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphComponent.cs new file mode 100644 index 0000000000..7fae089564 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphComponent.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + public class GlyphComponent : FontTableElement + { + public CompositeGlyphFlags Flags { get; set; } + public ushort GlyphIndex { get; set; } + public short Argument1 { get; set; } + public short Argument2 { get; set; } + + // Transformation fields (F2Dot14 format) + public short Scale { get; set; } + public short XScale { get; set; } + public short YScale { get; set; } + public short Scale01 { get; set; } + public short Scale10 { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian((ushort)Flags); + writer.WriteUInt16BigEndian(GlyphIndex); + + if ((Flags & CompositeGlyphFlags.ARG_1_AND_2_ARE_WORDS) != 0) + { + writer.WriteInt16BigEndian(Argument1); + writer.WriteInt16BigEndian(Argument2); + } + else + { + writer.Write((byte)Argument1); + writer.Write((byte)Argument2); + } + + if ((Flags & CompositeGlyphFlags.WE_HAVE_A_SCALE) != 0) + { + writer.WriteInt16BigEndian(Scale); + } + else if ((Flags & CompositeGlyphFlags.WE_HAVE_AN_X_AND_Y_SCALE) != 0) + { + writer.WriteInt16BigEndian(XScale); + writer.WriteInt16BigEndian(YScale); + } + else if ((Flags & CompositeGlyphFlags.WE_HAVE_A_TWO_BY_TWO) != 0) + { + writer.WriteInt16BigEndian(XScale); + writer.WriteInt16BigEndian(Scale01); + writer.WriteInt16BigEndian(Scale10); + writer.WriteInt16BigEndian(YScale); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphHeader.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphHeader.cs new file mode 100644 index 0000000000..82df7515e3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphHeader.cs @@ -0,0 +1,72 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + /// + /// Each glyph description begins with a header + /// + public class GlyphHeader : FontTableElement + { + internal GlyphHeader() + { + + } + + internal GlyphHeader(short numberOfContours, BoundingRectangle rect) + { + this.numberOfContours = numberOfContours; + xMin = rect.Xmin; + xMax = rect.Xmax; + yMin = rect.Ymin; + yMax = rect.Ymax; + } + public short numberOfContours { get; set; } + + /// + /// Minimum x for coordinate data. + /// + public short xMin { get; set; } + + /// + /// Minimum y for coordinate data. + /// + public short yMin { get; set; } + + /// + /// Maximum x for coordinate data. + /// + public short xMax { get; set; } + + /// + /// Maximum y for coordinate data. + /// + public short yMax { get; set; } + + public BoundingRectangle Bounds + { + get + { + return new BoundingRectangle(xMin, yMin, xMax, yMax); + } + } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteInt16BigEndian(numberOfContours); + writer.WriteInt16BigEndian(xMin); + writer.WriteInt16BigEndian(yMin); + writer.WriteInt16BigEndian(xMax); + writer.WriteInt16BigEndian(yMax); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphPoint.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphPoint.cs new file mode 100644 index 0000000000..10b78d6608 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphPoint.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + public class GlyphPoint + { + public bool OnCurve { get; set; } + public short X { get; set; } + public short Y { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetProcessor.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetProcessor.cs new file mode 100644 index 0000000000..09edf4ad88 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetProcessor.cs @@ -0,0 +1,61 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + internal class GlyphSubsetProcessor + { + private readonly GlyfTable _originalGlyphTable; + + public GlyphSubsetProcessor(GlyfTable originalGlyphTable) + { + _originalGlyphTable = originalGlyphTable; + } + + public GlyphSubsetResult CreateSubset(HashSet glyphIds) + { + var sortedIds = glyphIds.OrderBy(id => id).ToList(); + var newGlyphs = new List(); + var offsets = new List(); + + uint currentOffset = 0; + foreach (var id in sortedIds) + { + var glyph = _originalGlyphTable.GetGlyph(id); + newGlyphs.Add(glyph); + + offsets.Add(currentOffset); + currentOffset += AlignTo4Bytes(glyph.GetSize()); + } + + // Loca kräver en extra offset efter sista glyfen + offsets.Add(currentOffset); + + var newGlyphTable = new GlyfTable(newGlyphs); + return new GlyphSubsetResult + { + GlyfTable = newGlyphTable, + LocaOffsets = offsets + }; + } + + private uint AlignTo4Bytes(int size) + { + return (uint)((size + 3) & ~3); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetResult.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetResult.cs new file mode 100644 index 0000000000..b399b1c3ea --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/GlyphSubsetResult.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + + internal class GlyphSubsetResult + { + public GlyfTable GlyfTable { get; set; } + public List LocaOffsets { get; set; } + + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/CompositeGlyphDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/CompositeGlyphDeserializer.cs new file mode 100644 index 0000000000..7ac792a911 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/CompositeGlyphDeserializer.cs @@ -0,0 +1,80 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph.Serialization +{ + internal static class CompositeGlyphDeserializer + { + public static CompositeGlyph Deserialize(FontsBinaryReader reader) + { + var glyph = new CompositeGlyph(); + bool moreComponents; + + do + { + var flags = (CompositeGlyphFlags)reader.ReadUInt16BigEndian(); + var glyphIndex = reader.ReadUInt16BigEndian(); + + short arg1, arg2; + if ((flags & CompositeGlyphFlags.ARG_1_AND_2_ARE_WORDS) != 0) + { + arg1 = reader.ReadInt16BigEndian(); + arg2 = reader.ReadInt16BigEndian(); + } + else + { + arg1 = reader.ReadByte(); + arg2 = reader.ReadByte(); + } + + var component = new GlyphComponent + { + Flags = flags, + GlyphIndex = glyphIndex, + Argument1 = arg1, + Argument2 = arg2 + }; + + if ((flags & CompositeGlyphFlags.WE_HAVE_A_SCALE) != 0) + { + component.Scale = reader.ReadInt16BigEndian(); + } + else if ((flags & CompositeGlyphFlags.WE_HAVE_AN_X_AND_Y_SCALE) != 0) + { + component.XScale = reader.ReadInt16BigEndian(); + component.YScale = reader.ReadInt16BigEndian(); + } + else if ((flags & CompositeGlyphFlags.WE_HAVE_A_TWO_BY_TWO) != 0) + { + component.XScale = reader.ReadInt16BigEndian(); + component.Scale01 = reader.ReadInt16BigEndian(); + component.Scale10 = reader.ReadInt16BigEndian(); + component.YScale = reader.ReadInt16BigEndian(); + } + + glyph.Components.Add(component); + moreComponents = (flags & CompositeGlyphFlags.MORE_COMPONENTS) != 0; + + } while (moreComponents); + + if ((glyph.Components.Last().Flags & CompositeGlyphFlags.WE_HAVE_INSTRUCTIONS) != 0) + { + var instructionLength = reader.ReadUInt16BigEndian(); + glyph.Instructions = reader.ReadBytes(instructionLength); + } + + return glyph; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/GlyphDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/GlyphDeserializer.cs new file mode 100644 index 0000000000..ac73ccd3cd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/GlyphDeserializer.cs @@ -0,0 +1,49 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Glyph.Serialization +{ + internal static class GlyphDeserializer + { + public static Glyph Deserialize(FontsBinaryReader reader) + { + var numberOfContours = reader.ReadInt16BigEndian(); + var xMin = reader.ReadInt16BigEndian(); + var yMin = reader.ReadInt16BigEndian(); + var xMax = reader.ReadInt16BigEndian(); + var yMax = reader.ReadInt16BigEndian(); + + var glyph = new Glyph + { + Header = new GlyphHeader + { + numberOfContours = numberOfContours, + xMin = xMin, + yMin = yMin, + xMax = xMax, + yMax = yMax + } + }; + + if (numberOfContours > 0) + { + glyph.SimpleData = SimpleGlyphDeserializer.Deserialize(reader, numberOfContours); + } + else if (numberOfContours < 0) + { + glyph.CompositeData = CompositeGlyphDeserializer.Deserialize(reader); + } + + return glyph; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/SimpleGlyphDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/SimpleGlyphDeserializer.cs new file mode 100644 index 0000000000..1056df9c86 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/Serialization/SimpleGlyphDeserializer.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph.Serialization +{ + internal static class SimpleGlyphDeserializer + { + public static SimpleGlyph Deserialize(FontsBinaryReader reader, int numberOfContours) + { + var glyph = new SimpleGlyph(); + + // 1. Read endPtsOfContours + glyph.EndPtsOfContours = new ushort[numberOfContours]; + for (int i = 0; i < numberOfContours; i++) + { + glyph.EndPtsOfContours[i] = reader.ReadUInt16BigEndian(); + } + + // 2. Read instructions + var instructionLength = reader.ReadUInt16BigEndian(); + glyph.Instructions = reader.ReadBytes(instructionLength); + + // 3. Calculate number of points + int pointCount = glyph.EndPtsOfContours[numberOfContours - 1] + 1; + + // 4. Read flags (needed to know how to parse coordinates) + var flagRuns = new List(); + var expandedFlags = new List(); + + while (expandedFlags.Count < pointCount) + { + byte flag = reader.ReadByte(); + byte repeatCount = 0; + + if ((flag & 0x08) != 0) // repeat flag + { + repeatCount = reader.ReadByte(); + } + + flagRuns.Add(new FlagRun { Flag = flag, RepeatCount = repeatCount }); + + expandedFlags.Add(flag); + for (int r = 0; r < repeatCount; r++) + expandedFlags.Add(flag); + } + + glyph.FlagRuns = flagRuns; + glyph.Flags = expandedFlags; + + // 5. Read X-coordinates by measuring the byte block + // We must do this because TrueType uses a delta-encoding where + // some points consume 0, 1, or 2 bytes depending on flags. + long xStart = reader.BaseStream.Position; + for (int i = 0; i < pointCount; i++) + { + byte flag = expandedFlags[i]; + if ((flag & 0x02) != 0) // X-Short + { + reader.ReadByte(); + } + else if ((flag & 0x10) == 0) // Not same (consumes 2 bytes) + { + reader.ReadInt16BigEndian(); + } + // If (flag & 0x10) is set and X-Short is NOT set, 0 bytes are consumed (Same as prev) + } + long xEnd = reader.BaseStream.Position; + int xLength = (int)(xEnd - xStart); + + // Go back and grab the raw bytes + reader.BaseStream.Position = xStart; + glyph.XBytes = reader.ReadBytes(xLength); + + // 6. Read Y-coordinates by measuring the byte block + long yStart = reader.BaseStream.Position; + for (int i = 0; i < pointCount; i++) + { + byte flag = expandedFlags[i]; + if ((flag & 0x04) != 0) // Y-Short + { + reader.ReadByte(); + } + else if ((flag & 0x20) == 0) // Not same (consumes 2 bytes) + { + reader.ReadInt16BigEndian(); + } + } + long yEnd = reader.BaseStream.Position; + int yLength = (int)(yEnd - yStart); + + reader.BaseStream.Position = yStart; + glyph.YBytes = reader.ReadBytes(yLength); + + return glyph; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/SimpleGlyph.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/SimpleGlyph.cs new file mode 100644 index 0000000000..5a035a41e1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/SimpleGlyph.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + public class SimpleGlyph : FontTableElement + { + public ushort[] EndPtsOfContours { get; set; } + public byte[] Instructions { get; set; } + public List Points { get; set; } = new(); + + public List Flags { get; set; } = new List(); + + public List FlagRuns { get; set; } = new List(); + + + // Raw encoded coordinate bytes for X and Y + public byte[] XBytes { get; set; } + public byte[] YBytes { get; set; } + + + /// + /// Serialize according to OpenType "Simple glyph description". + /// + internal override void Serialize(FontsBinaryWriter writer) + { + + + // Write endPtsOfContours + foreach (var endPt in EndPtsOfContours) + writer.WriteUInt16BigEndian(endPt); + + // Write instructions + writer.WriteUInt16BigEndian((ushort)Instructions.Length); + writer.Write(Instructions); + + // Write flags using original runs + foreach (var run in FlagRuns) + { + writer.Write(run.Flag); + if ((run.Flag & 0x08) != 0) + { + writer.Write(run.RepeatCount); + } + } + + // Write coordinates + writer.Write(XBytes); + writer.Write(YBytes); + + + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Glyph/StandardMacGlyphNames.cs b/src/EPPlus.Fonts.OpenType/Tables/Glyph/StandardMacGlyphNames.cs new file mode 100644 index 0000000000..8ebf558bf1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Glyph/StandardMacGlyphNames.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Glyph +{ + internal static class StandardMacGlyphNames + { + private static readonly string[] Names = new string[258] + { + ".notdef", "null", "nonmarkingreturn", "space", "exclam", "quotedbl", + "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", + "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + "colon", "semicolon", "less", "equal", "greater", "question", "at", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", + "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", + "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", + "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + "dagger", "degree", "cent", "sterling", "section", "bullet", + "paragraph", "germandbls", "registered", "copyright", "trademark", + "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", + "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", + "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", + "Omega", "ae", "oslash", "questiondown", "exclamdown", + "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", + "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", + "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", + "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", + "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", + "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", + "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", + "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", + "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", + "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", + "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", + "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", + "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", + "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", + "Cacute", "cacute", "Ccaron", "ccaron", "dcroat" + }; + + public static string NameFromIndex(ushort index) + { + return index < Names.Length ? Names[index] : $".unknown{index}"; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/AnchorTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/AnchorTable.cs new file mode 100644 index 0000000000..6cefcfabc9 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/AnchorTable.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Anchor table (shared across lookup types) + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups +{ + /// + /// Anchor table defining a position attachment point. + /// Used by MarkToBase, MarkToLigature, MarkToMark, and Cursive attachment. + /// Three formats exist, but we implement the most common ones. + /// + public class AnchorTable + { + /// + /// Format identifier (1, 2, or 3) + /// + public ushort AnchorFormat { get; internal set; } + + /// + /// X coordinate of anchor point (in design units) + /// + public short XCoordinate { get; internal set; } + + /// + /// Y coordinate of anchor point (in design units) + /// + public short YCoordinate { get; internal set; } + + /// + /// Anchor point index (Format 2 only) + /// Used to identify which contour point to use + /// + public ushort AnchorPoint { get; internal set; } + + /// + /// Offset to Device table for X coordinate (Format 3 only) + /// We don't implement device tables yet - stored for completeness + /// + public ushort XDeviceOffset { get; internal set; } + + /// + /// Offset to Device table for Y coordinate (Format 3 only) + /// We don't implement device tables yet - stored for completeness + /// + public ushort YDeviceOffset { get; internal set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/GposSubTableBase.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/GposSubTableBase.cs new file mode 100644 index 0000000000..c691b39647 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/GposSubTableBase.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS subtable base class + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups +{ + /// + /// Base class for all GPOS subtables. + /// Each lookup type has one or more subtable formats that inherit from this. + /// + public abstract class GposSubTableBase : FontTableElement + { + // Currently empty - provides type safety and future extensibility + // All GPOS subtables inherit from this for polymorphic storage in Lookup.SubTables + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1 .cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1 .cs new file mode 100644 index 0000000000..3504fb8ae6 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1 .cs @@ -0,0 +1,98 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 1 (Single Adjustment) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1 +{ + /// + /// GPOS Lookup Type 1, Format 1: Single Adjustment Positioning + /// Applies the same ValueRecord to all glyphs in the Coverage table. + /// Used for uniform adjustments like raising all superscripts by the same amount. + /// + public class SinglePosSubTableFormat1 : GposSubTableBase + { + /// + /// Format identifier: 1 + /// + public ushort SubtableFormat { get; internal set; } + + /// + /// Offset to Coverage table (from beginning of SinglePos subtable) + /// + public ushort CoverageOffset { get; internal set; } + + /// + /// Defines the types of data in the ValueRecord + /// + public ushort ValueFormat { get; internal set; } + + /// + /// Coverage table - defines which glyphs this adjustment applies to + /// + public CoverageTable Coverage { get; internal set; } + + /// + /// Single ValueRecord applied to all covered glyphs + /// + public ValueRecord Value { get; internal set; } + + /// + /// Tries to get the positioning adjustment for a glyph. + /// + /// The glyph ID to look up + /// The ValueRecord if found + /// True if the glyph is in coverage + public bool TryGetAdjustment(ushort glyphId, out ValueRecord value) + { + if (Coverage != null && Coverage.IsCovered(glyphId)) + { + value = Value; + return true; + } + + value = null; + return false; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + long subtableStart = writer.BaseStream.Position; + + // Write header + writer.WriteUInt16BigEndian(SubtableFormat); // 1 + + long coverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Coverage offset placeholder + + writer.WriteUInt16BigEndian(ValueFormat); + + // Write ValueRecord + ValueRecordSerializer.Serialize(writer, Value, ValueFormat); + + // Write Coverage table + if (Coverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + // Update offset + writer.BaseStream.Seek(coverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + // Serialize coverage + Coverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1Deserializer.cs new file mode 100644 index 0000000000..c982e99ada --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat1Deserializer.cs @@ -0,0 +1,104 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 1 Format 1 Deserializer + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1 +{ + /// + /// Deserializer for GPOS Lookup Type 1, Format 1: Single Adjustment Positioning + /// + internal class SinglePosSubTableFormat1Deserializer + { + private readonly FontsBinaryReader _reader; + + public SinglePosSubTableFormat1Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + /// + /// Deserializes a SinglePos Format 1 subtable from the current stream position. + /// + /// Absolute offset where this subtable starts + /// Deserialized SinglePosSubTableFormat1 + public SinglePosSubTableFormat1 Deserialize(long subtableStartOffset) + { + _reader.BaseStream.Seek(subtableStartOffset, SeekOrigin.Begin); + + var subtable = new SinglePosSubTableFormat1 + { + SubtableFormat = _reader.ReadUInt16BigEndian(), + CoverageOffset = _reader.ReadUInt16BigEndian(), + ValueFormat = _reader.ReadUInt16BigEndian() + }; + + // Read the single ValueRecord + subtable.Value = ReadValueRecord(subtable.ValueFormat); + + // Read Coverage table + if (subtable.CoverageOffset > 0) + { + long coveragePos = subtableStartOffset + subtable.CoverageOffset; + _reader.BaseStream.Seek(coveragePos, SeekOrigin.Begin); + + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + + if (coverageFormat == 1) + { + subtable.Coverage = new CoverageTableFormat1Deserializer(_reader) + .Deserialize(coveragePos); + } + else if (coverageFormat == 2) + { + subtable.Coverage = new CoverageTableFormat2Deserializer(_reader) + .Deserialize(coveragePos); + } + } + + return subtable; + } + + /// + /// Reads a ValueRecord based on the ValueFormat flags. + /// ValueFormat is a bit field indicating which fields are present. + /// + private ValueRecord ReadValueRecord(ushort valueFormat) + { + var record = new ValueRecord(); + + // Bit 0x0001: XPlacement + if ((valueFormat & 0x0001) != 0) + record.XPlacement = _reader.ReadInt16BigEndian(); + + // Bit 0x0002: YPlacement + if ((valueFormat & 0x0002) != 0) + record.YPlacement = _reader.ReadInt16BigEndian(); + + // Bit 0x0004: XAdvance + if ((valueFormat & 0x0004) != 0) + record.XAdvance = _reader.ReadInt16BigEndian(); + + // Bit 0x0008: YAdvance + if ((valueFormat & 0x0008) != 0) + record.YAdvance = _reader.ReadInt16BigEndian(); + + // Bits 0x0010-0x0080: Device tables (not implemented yet) + // Skip for now - we only need basic positioning + + return record; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2 .cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2 .cs new file mode 100644 index 0000000000..770cc6dd8e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2 .cs @@ -0,0 +1,115 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 1 Format 2 (Single Adjustment) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1 +{ + /// + /// GPOS Lookup Type 1, Format 2: Single Adjustment Positioning + /// Applies different ValueRecords to each glyph in the Coverage table. + /// Used when each glyph needs individual positioning (e.g., optical adjustments). + /// + public class SinglePosSubTableFormat2 : GposSubTableBase + { + /// + /// Format identifier: 2 + /// + public ushort SubtableFormat { get; internal set; } + + /// + /// Offset to Coverage table (from beginning of SinglePos subtable) + /// + public ushort CoverageOffset { get; internal set; } + + /// + /// Defines the types of data in the ValueRecords + /// + public ushort ValueFormat { get; internal set; } + + /// + /// Number of ValueRecords (must equal coverage count) + /// + public ushort ValueCount { get; internal set; } + + /// + /// Coverage table - defines which glyphs this adjustment applies to + /// + public CoverageTable Coverage { get; internal set; } + + /// + /// Array of ValueRecords, one per covered glyph. + /// Index corresponds to coverage index. + /// + public ValueRecord[] Values { get; internal set; } + + /// + /// Tries to get the positioning adjustment for a glyph. + /// + /// The glyph ID to look up + /// The ValueRecord if found + /// True if the glyph is in coverage + public bool TryGetAdjustment(ushort glyphId, out ValueRecord value) + { + if (Coverage != null) + { + int coverageIndex = Coverage.GetGlyphIndex(glyphId); + if (coverageIndex >= 0 && coverageIndex < Values.Length) + { + value = Values[coverageIndex]; + return true; + } + } + + value = null; + return false; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + long subtableStart = writer.BaseStream.Position; + + // Write header + writer.WriteUInt16BigEndian(SubtableFormat); // 2 + + long coverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Coverage offset placeholder + + writer.WriteUInt16BigEndian(ValueFormat); + writer.WriteUInt16BigEndian(ValueCount); + + // Write ValueRecords array + if (Values != null) + { + foreach (var value in Values) + { + ValueRecordSerializer.Serialize(writer, value, ValueFormat); + } + } + + // Write Coverage table + if (Coverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + // Update offset + writer.BaseStream.Seek(coverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + // Serialize coverage + Coverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2Deserializer.cs new file mode 100644 index 0000000000..4711bf6f3d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType1/SinglePosSubTableFormat2Deserializer.cs @@ -0,0 +1,109 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 1 Format 2 Deserializer + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1 +{ + /// + /// Deserializer for GPOS Lookup Type 1, Format 2: Single Adjustment Positioning + /// Each glyph in coverage gets its own individual ValueRecord. + /// + internal class SinglePosSubTableFormat2Deserializer + { + private readonly FontsBinaryReader _reader; + + public SinglePosSubTableFormat2Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + /// + /// Deserializes a SinglePos Format 2 subtable from the current stream position. + /// + /// Absolute offset where this subtable starts + /// Deserialized SinglePosSubTableFormat2 + public SinglePosSubTableFormat2 Deserialize(long subtableStartOffset) + { + // Seek to subtable start + _reader.BaseStream.Seek(subtableStartOffset, SeekOrigin.Begin); + + var subtable = new SinglePosSubTableFormat2 + { + SubtableFormat = _reader.ReadUInt16BigEndian(), + CoverageOffset = _reader.ReadUInt16BigEndian(), + ValueFormat = _reader.ReadUInt16BigEndian(), + ValueCount = _reader.ReadUInt16BigEndian() + }; + + // Read array of ValueRecords + subtable.Values = new ValueRecord[subtable.ValueCount]; + for (int i = 0; i < subtable.ValueCount; i++) + { + subtable.Values[i] = ReadValueRecord(subtable.ValueFormat); + } + + // Read Coverage table + if (subtable.CoverageOffset > 0) + { + long coveragePos = subtableStartOffset + subtable.CoverageOffset; + _reader.BaseStream.Seek(coveragePos, SeekOrigin.Begin); + + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + + if (coverageFormat == 1) + { + subtable.Coverage = new CoverageTableFormat1Deserializer(_reader) + .Deserialize(coveragePos); + } + else if (coverageFormat == 2) + { + subtable.Coverage = new CoverageTableFormat2Deserializer(_reader) + .Deserialize(coveragePos); + } + } + + return subtable; + } + + /// + /// Reads a ValueRecord based on the ValueFormat flags. + /// ValueFormat is a bit field indicating which fields are present. + /// + private ValueRecord ReadValueRecord(ushort valueFormat) + { + var record = new ValueRecord(); + + // Bit 0x0001: XPlacement + if ((valueFormat & 0x0001) != 0) + record.XPlacement = _reader.ReadInt16BigEndian(); + + // Bit 0x0002: YPlacement + if ((valueFormat & 0x0002) != 0) + record.YPlacement = _reader.ReadInt16BigEndian(); + + // Bit 0x0004: XAdvance + if ((valueFormat & 0x0004) != 0) + record.XAdvance = _reader.ReadInt16BigEndian(); + + // Bit 0x0008: YAdvance + if ((valueFormat & 0x0008) != 0) + record.YAdvance = _reader.ReadInt16BigEndian(); + + // Bits 0x0010-0x0080: Device tables (not implemented yet) + // Skip for now - we only need basic positioning + + return record; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTable.cs new file mode 100644 index 0000000000..c17c442721 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTable.cs @@ -0,0 +1,60 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS PairPos subtable (Type 2) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// GPOS Lookup Type 2: Pair Adjustment Positioning Subtable. + /// Used for kerning - adjusting spacing between specific glyph pairs. + /// Abstract base for Format 1 and Format 2. + /// + public abstract class PairPosSubTable : GposSubTableBase + { + /// + /// Subtable format (1 or 2) + /// + public ushort SubtableFormat { get; set; } + + /// + /// Coverage table - which glyphs are affected + /// + public CoverageTable Coverage { get; set; } + + /// + /// Value format for first glyph in pair + /// + public ushort ValueFormat1 { get; set; } + + /// + /// Value format for second glyph in pair + /// + public ushort ValueFormat2 { get; set; } + + + /// + /// Gets the positioning adjustment for a specific glyph pair + /// + /// First glyph in pair + /// Second glyph in pair + /// Adjustment for first glyph (output) + /// Adjustment for second glyph (output) + /// True if pair has positioning data + public abstract bool TryGetPairAdjustment( + ushort firstGlyph, + ushort secondGlyph, + out ValueRecord value1, + out ValueRecord value2); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1.cs new file mode 100644 index 0000000000..0ab33ed3fc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1.cs @@ -0,0 +1,140 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS PairPos Format 1 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// PairPos Format 1: Adjustments for glyph pairs listed explicitly. + /// Used when there are few pairs (e.g., specific kerning pairs like AV, AW). + /// + public class PairPosSubTableFormat1 : PairPosSubTable + { + /// + /// Pair sets indexed by coverage index + /// + public List PairSets { get; set; } + + public override bool TryGetPairAdjustment( + ushort firstGlyph, + ushort secondGlyph, + out ValueRecord value1, + out ValueRecord value2) + { + value1 = null; + value2 = null; + + // Check if first glyph is covered + int coverageIndex = Coverage?.GetGlyphIndex(firstGlyph) ?? -1; + if (coverageIndex < 0 || coverageIndex >= (PairSets?.Count ?? 0)) + return false; + + var pairSet = PairSets[coverageIndex]; + if (pairSet?.PairValueRecords == null || pairSet.PairValueRecords.Count == 0) + return false; + + // Binary search for matching second glyph + // PairValueRecords are guaranteed sorted by SecondGlyph per OpenType spec + int left = 0; + int right = pairSet.PairValueRecords.Count - 1; + + while (left <= right) + { + int mid = left + (right - left) / 2; + ushort midGlyphId = pairSet.PairValueRecords[mid].SecondGlyph; + + if (midGlyphId == secondGlyph) + { + // Found match + var record = pairSet.PairValueRecords[mid]; + value1 = record.Value1; + value2 = record.Value2; + return true; + } + + if (midGlyphId < secondGlyph) + left = mid + 1; + else + right = mid - 1; + } + + return false; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + long subtableStart = writer.BaseStream.Position; + + // Write header + writer.WriteUInt16BigEndian(SubtableFormat); // 1 + + long coverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Coverage offset placeholder + + writer.WriteUInt16BigEndian(ValueFormat1); + writer.WriteUInt16BigEndian(ValueFormat2); + writer.WriteUInt16BigEndian((ushort)PairSets.Count); + + // Reserve space for PairSet offsets + long pairSetOffsetsPos = writer.BaseStream.Position; + for (int i = 0; i < PairSets.Count; i++) + { + writer.WriteUInt16BigEndian(0); // Placeholder + } + + // Write PairSets + for (int i = 0; i < PairSets.Count; i++) + { + var pairSet = PairSets[i]; + if (pairSet == null || pairSet.PairValueRecords.Count == 0) + { + continue; // Leave offset as 0 + } + + long pairSetStart = writer.BaseStream.Position; + ushort pairSetOffset = (ushort)(pairSetStart - subtableStart); + + // Write PairSet + writer.WriteUInt16BigEndian((ushort)pairSet.PairValueRecords.Count); + + foreach (var record in pairSet.PairValueRecords) + { + writer.WriteUInt16BigEndian(record.SecondGlyph); + ValueRecordSerializer.Serialize(writer, record.Value1, ValueFormat1); + ValueRecordSerializer.Serialize(writer, record.Value2, ValueFormat2); + } + + // Update PairSet offset + long currentPos = writer.BaseStream.Position; + writer.BaseStream.Seek(pairSetOffsetsPos + (i * 2), System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(pairSetOffset); + writer.BaseStream.Seek(currentPos, System.IO.SeekOrigin.Begin); + } + + // Write Coverage table + if (Coverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + // Update offset + writer.BaseStream.Seek(coverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + // Serialize coverage + Coverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1Deserializer.cs new file mode 100644 index 0000000000..59c02b07bd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat1Deserializer.cs @@ -0,0 +1,118 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/09/2026 EPPlus Software AB GPOS PairPos Format 1 deserializer + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// Deserializes PairPos Format 1 subtables (explicit glyph pairs with kerning) + /// + internal class PairPosSubTableFormat1Deserializer + { + private readonly FontsBinaryReader _reader; + + public PairPosSubTableFormat1Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public PairPosSubTableFormat1 Deserialize(long subtableStart) + { + _reader.BaseStream.Seek(subtableStart, SeekOrigin.Begin); + + var table = new PairPosSubTableFormat1(); + + // Read header + table.SubtableFormat = _reader.ReadUInt16BigEndian(); // Should be 1 + ushort coverageOffset = _reader.ReadUInt16BigEndian(); + table.ValueFormat1 = _reader.ReadUInt16BigEndian(); + table.ValueFormat2 = _reader.ReadUInt16BigEndian(); + ushort pairSetCount = _reader.ReadUInt16BigEndian(); + + // Read PairSet offsets + var pairSetOffsets = new ushort[pairSetCount]; + for (int i = 0; i < pairSetCount; i++) + { + pairSetOffsets[i] = _reader.ReadUInt16BigEndian(); + } + + // Read Coverage table + if (coverageOffset > 0) + { + long coveragePos = subtableStart + coverageOffset; + _reader.BaseStream.Seek(coveragePos, SeekOrigin.Begin); + + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + + if (coverageFormat == 1) + { + table.Coverage = new CoverageTableFormat1Deserializer(_reader) + .Deserialize(coveragePos); + } + else if (coverageFormat == 2) + { + table.Coverage = new CoverageTableFormat2Deserializer(_reader) + .Deserialize(coveragePos); + } + } + + // Read PairSets + table.PairSets = new List(); + + for (int i = 0; i < pairSetCount; i++) + { + if (pairSetOffsets[i] == 0) + { + table.PairSets.Add(null); + continue; + } + + long pairSetPos = subtableStart + pairSetOffsets[i]; + _reader.BaseStream.Seek(pairSetPos, SeekOrigin.Begin); + + var pairSet = ReadPairSet(table.ValueFormat1, table.ValueFormat2); + table.PairSets.Add(pairSet); + } + + return table; + } + + private PairSet ReadPairSet(ushort valueFormat1, ushort valueFormat2) + { + var pairSet = new PairSet(); + + ushort pairValueCount = _reader.ReadUInt16BigEndian(); + pairSet.PairValueRecords = new List(); + + for (int i = 0; i < pairValueCount; i++) + { + var record = new PairValueRecord(); + + // Read second glyph ID + record.SecondGlyph = _reader.ReadUInt16BigEndian(); + + // Read Value1 (adjustments for first glyph) + record.Value1 = ValueRecord.Read(_reader, valueFormat1); + + // Read Value2 (adjustments for second glyph) + record.Value2 = ValueRecord.Read(_reader, valueFormat2); + + pairSet.PairValueRecords.Add(record); + } + + return pairSet; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2.cs new file mode 100644 index 0000000000..95797b15be --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2.cs @@ -0,0 +1,187 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// PairPos Format 2: Class-based kerning. + /// Uses ClassDef1/ClassDef2 and a class matrix. + /// + public class PairPosSubTableFormat2 : PairPosSubTable + { + /// + /// Class definition for first glyph (ClassDef1) + /// + public ClassDefTable ClassDef1 { get; set; } + + /// + /// Class definition for second glyph (ClassDef2) + /// + public ClassDefTable ClassDef2 { get; set; } + + /// + /// Number of classes in ClassDef1 + /// + public ushort Class1Count { get; set; } + + /// + /// Number of classes in ClassDef2 + /// + public ushort Class2Count { get; set; } + + /// + /// Matrix [Class1Count, Class2Count] of pair value records + /// + public PairValueRecord[,] ClassMatrix { get; set; } + + public override bool TryGetPairAdjustment( + ushort firstGlyph, + ushort secondGlyph, + out ValueRecord value1, + out ValueRecord value2) + { + value1 = null; + value2 = null; + + + if (Coverage == null || ClassDef1 == null || ClassDef2 == null || ClassMatrix == null) + { + return false; + } + + // First glyph must be in coverage + int coverageIndex = Coverage.GetGlyphIndex(firstGlyph); + + if (coverageIndex < 0) + { + return false; + } + + int class1 = ClassDef1.GetClass(firstGlyph); + int class2 = ClassDef2.GetClass(secondGlyph); + + + if (class1 < 0 || class2 < 0) + { + return false; + } + + if (class1 >= Class1Count || class2 >= Class2Count) + { + return false; + } + + var record = ClassMatrix[class1, class2]; + + if (record == null) + { + return false; + } + + if (record.Value1 == null && record.Value2 == null) + { + return false; + } + + value1 = record.Value1; + value2 = record.Value2; + + return true; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + long subtableStart = writer.BaseStream.Position; + + // Header + writer.WriteUInt16BigEndian(SubtableFormat); // 2 + + long coverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Coverage offset placeholder + + long classDef1OffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // ClassDef1 offset placeholder + + long classDef2OffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // ClassDef2 offset placeholder + + writer.WriteUInt16BigEndian(ValueFormat1); + writer.WriteUInt16BigEndian(ValueFormat2); + + writer.WriteUInt16BigEndian(Class1Count); + writer.WriteUInt16BigEndian(Class2Count); + + // Class1Record/Class2Record matrix + for (int i = 0; i < Class1Count; i++) + { + for (int j = 0; j < Class2Count; j++) + { + var record = ClassMatrix?[i, j]; + + if (record != null) + { + record.Value1?.Write(writer, ValueFormat1); + record.Value2?.Write(writer, ValueFormat2); + } + else + { + // Write empty value records + var empty = new ValueRecord(); + empty.Write(writer, ValueFormat1); + empty.Write(writer, ValueFormat2); + } + } + } + + // Coverage + if (Coverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + writer.BaseStream.Seek(coverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + Coverage.Serialize(writer); + } + + // ClassDef1 + if (ClassDef1 != null) + { + ushort classDef1Offset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + writer.BaseStream.Seek(classDef1OffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(classDef1Offset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + ClassDef1.Serialize(writer); + } + + // ClassDef2 + if (ClassDef2 != null) + { + ushort classDef2Offset = (ushort)(writer.BaseStream.Position - subtableStart); + long resumePos = writer.BaseStream.Position; + + writer.BaseStream.Seek(classDef2OffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(classDef2Offset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + ClassDef2.Serialize(writer); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2Deserializer.cs new file mode 100644 index 0000000000..6a2d0689e4 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairPosSubTableFormat2Deserializer.cs @@ -0,0 +1,109 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.ClassDef.IO; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// Deserializes PairPos Format 2 subtables (class-based kerning) + /// + internal class PairPosSubTableFormat2Deserializer + { + private readonly FontsBinaryReader _reader; + + public PairPosSubTableFormat2Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public PairPosSubTableFormat2 Deserialize(long subtableStart) + { + _reader.BaseStream.Seek(subtableStart, SeekOrigin.Begin); + + var table = new PairPosSubTableFormat2(); + // Header + table.SubtableFormat = _reader.ReadUInt16BigEndian(); // Should be 2 + + ushort coverageOffset = _reader.ReadUInt16BigEndian(); + table.ValueFormat1 = _reader.ReadUInt16BigEndian(); + table.ValueFormat2 = _reader.ReadUInt16BigEndian(); + + ushort classDef1Offset = _reader.ReadUInt16BigEndian(); + ushort classDef2Offset = _reader.ReadUInt16BigEndian(); + + table.Class1Count = _reader.ReadUInt16BigEndian(); + table.Class2Count = _reader.ReadUInt16BigEndian(); + + // Read class matrix + table.ClassMatrix = new PairValueRecord[table.Class1Count, table.Class2Count]; + + for (int i = 0; i < table.Class1Count; i++) + { + for (int j = 0; j < table.Class2Count; j++) + { + var value1 = ValueRecord.Read(_reader, table.ValueFormat1); + var value2 = ValueRecord.Read(_reader, table.ValueFormat2); + + table.ClassMatrix[i, j] = new PairValueRecord + { + Value1 = value1, + Value2 = value2 + }; + } + } + + // Coverage + if (coverageOffset > 0) + { + long coveragePos = subtableStart + coverageOffset; + _reader.BaseStream.Seek(coveragePos, SeekOrigin.Begin); + + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + if (coverageFormat == 1) + { + table.Coverage = new CoverageTableFormat1Deserializer(_reader) + .Deserialize(coveragePos); + } + else if (coverageFormat == 2) + { + table.Coverage = new CoverageTableFormat2Deserializer(_reader) + .Deserialize(coveragePos); + } + } + + // ClassDef1 + if (classDef1Offset > 0) + { + long classDef1Pos = subtableStart + classDef1Offset; + _reader.BaseStream.Seek(classDef1Pos, SeekOrigin.Begin); + + table.ClassDef1 = new ClassDefTableDeserializer(_reader) + .Deserialize(classDef1Pos); + } + + // ClassDef2 + if (classDef2Offset > 0) + { + long classDef2Pos = subtableStart + classDef2Offset; + _reader.BaseStream.Seek(classDef2Pos, SeekOrigin.Begin); + + table.ClassDef2 = new ClassDefTableDeserializer(_reader) + .Deserialize(classDef2Pos); + } + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairSet.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairSet.cs new file mode 100644 index 0000000000..8a2f87c582 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairSet.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS PairSet + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// PairSet - list of pairs for a specific first glyph + /// + public class PairSet + { + public List PairValueRecords { get; set; } + + internal void Serialize(FontsBinaryWriter writer, ushort valueFormat1, ushort valueFormat2) + { + writer.WriteUInt16BigEndian((ushort)(PairValueRecords?.Count ?? 0)); + + if (PairValueRecords != null) + { + foreach (var record in PairValueRecords) + { + record.Serialize(writer, valueFormat1, valueFormat2); + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairValueRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairValueRecord.cs new file mode 100644 index 0000000000..285d9f5f4d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType2/PairValueRecord.cs @@ -0,0 +1,43 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS PairValueRecord + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2 +{ + /// + /// Single pair value record + /// + public class PairValueRecord + { + /// + /// Glyph ID of second glyph in pair + /// + public ushort SecondGlyph { get; set; } + + /// + /// Positioning for first glyph + /// + public ValueRecord Value1 { get; set; } + + /// + /// Positioning for second glyph + /// + public ValueRecord Value2 { get; set; } + + internal void Serialize(FontsBinaryWriter writer, ushort valueFormat1, ushort valueFormat2) + { + writer.WriteUInt16BigEndian(SecondGlyph); + Value1?.Write(writer, valueFormat1); + Value2?.Write(writer, valueFormat2); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseArray.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseArray.cs new file mode 100644 index 0000000000..981e2b02bc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseArray.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS BaseArray (Type 4) + *************************************************************************************************/ + +using EPPlus.Fonts.OpenType.Tables.Name; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// Array of BaseRecords defining attachment points for base glyphs (letters). + /// One record per base glyph in coverage order. + /// + public class BaseArray + { + /// + /// Number of BaseRecords in the array + /// + public ushort BaseCount { get; internal set; } + + /// + /// Array of BaseRecords, one per base glyph in coverage order + /// + public BaseRecord[] Records { get; internal set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseRecord.cs new file mode 100644 index 0000000000..114d410385 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/BaseRecord.cs @@ -0,0 +1,35 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS BaseRecord (Type 4) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// Record defining attachment points for a base glyph (letter). + /// Contains one anchor per mark class. + /// + public class BaseRecord + { + /// + /// Array of offsets to Anchor tables (from beginning of BaseArray) + /// One offset per mark class (length = MarkClassCount from subtable) + /// + public ushort[] BaseAnchorOffsets { get; internal set; } + + /// + /// Array of Anchor tables defining attachment points for each mark class. + /// Index corresponds to mark class (e.g., [0] = top accents, [1] = bottom accents) + /// + public AnchorTable[] BaseAnchors { get; internal set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkArray.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkArray.cs new file mode 100644 index 0000000000..a3e194e96f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkArray.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS MarkArray (Type 4, 5, 6) + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// Array of MarkRecords defining attachment points for mark glyphs (accents). + /// Used by MarkToBase, MarkToLigature, and MarkToMark lookups. + /// + public class MarkArray + { + /// + /// Number of MarkRecords in the array + /// + public ushort MarkCount { get; internal set; } + + /// + /// Array of MarkRecords, one per mark glyph in coverage order + /// + public MarkRecord[] Records { get; internal set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkRecord.cs new file mode 100644 index 0000000000..cad6d5a95a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkRecord.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS MarkRecord (Type 4, 5, 6) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// Record defining a mark glyph's attachment point and class. + /// + public class MarkRecord + { + /// + /// Mark class value (which attachment class this mark belongs to) + /// Example: class 0 = top accents, class 1 = bottom accents + /// + public ushort MarkClass { get; internal set; } + + /// + /// Offset to Anchor table for this mark (from beginning of MarkArray) + /// + public ushort MarkAnchorOffset { get; internal set; } + + /// + /// Anchor table defining the attachment point on the mark glyph + /// + public AnchorTable MarkAnchor { get; internal set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1.cs new file mode 100644 index 0000000000..af0b422e69 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1.cs @@ -0,0 +1,260 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 4 (MarkToBase Attachment) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// GPOS Lookup Type 4, Format 1: MarkToBase Attachment Positioning + /// Positions mark glyphs (accents, diacritics) relative to base glyphs (letters). + /// Used for proper placement of é, ñ, ü, etc. + /// + public class MarkToBaseSubTableFormat1 : GposSubTableBase + { + /// + /// Format identifier: 1 (only format for MarkToBase) + /// + public ushort SubtableFormat { get; internal set; } + + /// + /// Offset to MarkCoverage table (from beginning of MarkToBase subtable) + /// + public ushort MarkCoverageOffset { get; internal set; } + + /// + /// Offset to BaseCoverage table (from beginning of MarkToBase subtable) + /// + public ushort BaseCoverageOffset { get; internal set; } + + /// + /// Number of mark classes (different attachment types) + /// + public ushort MarkClassCount { get; internal set; } + + /// + /// Offset to MarkArray table + /// + public ushort MarkArrayOffset { get; internal set; } + + /// + /// Offset to BaseArray table + /// + public ushort BaseArrayOffset { get; internal set; } + + /// + /// Coverage table defining which mark glyphs (accents) are covered + /// + public CoverageTable MarkCoverage { get; internal set; } + + /// + /// Coverage table defining which base glyphs (letters) are covered + /// + public CoverageTable BaseCoverage { get; internal set; } + + /// + /// Array of mark records (one per mark glyph in coverage order) + /// + public MarkArray MarkArray { get; internal set; } + + /// + /// Array of base records (one per base glyph in coverage order) + /// + public BaseArray BaseArray { get; internal set; } + + /// + /// Tries to get the positioning for a mark attached to a base. + /// + /// The mark glyph ID (e.g., combining acute accent) + /// The base glyph ID (e.g., letter 'e') + /// Anchor point on the mark + /// Anchor point on the base + /// True if attachment is defined + public bool TryGetAttachment(ushort markGlyphId, ushort baseGlyphId, + out AnchorTable markAnchor, out AnchorTable baseAnchor) + { + markAnchor = null; + baseAnchor = null; + + // Get mark index and class + int markIndex = MarkCoverage?.GetGlyphIndex(markGlyphId) ?? -1; + if (markIndex < 0 || markIndex >= MarkArray?.Records.Length) + return false; + + var markRecord = MarkArray.Records[markIndex]; + ushort markClass = markRecord.MarkClass; + + // Get base index + int baseIndex = BaseCoverage?.GetGlyphIndex(baseGlyphId) ?? -1; + if (baseIndex < 0 || baseIndex >= BaseArray?.Records.Length) + return false; + + var baseRecord = BaseArray.Records[baseIndex]; + + // Get anchors for this mark class + if (markClass >= baseRecord.BaseAnchors.Length) + return false; + + markAnchor = markRecord.MarkAnchor; + baseAnchor = baseRecord.BaseAnchors[markClass]; + + return markAnchor != null && baseAnchor != null; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + long subtableStart = writer.BaseStream.Position; + + // Write header + writer.WriteUInt16BigEndian(SubtableFormat); // 1 + + long markCoverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // MarkCoverage offset placeholder + + long baseCoverageOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // BaseCoverage offset placeholder + + writer.WriteUInt16BigEndian(MarkClassCount); + + long markArrayOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // MarkArray offset placeholder + + long baseArrayOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // BaseArray offset placeholder + + // Write MarkArray + long markArrayStart = writer.BaseStream.Position; + ushort markArrayOffset = (ushort)(markArrayStart - subtableStart); + + if (MarkArray != null) + { + writer.WriteUInt16BigEndian(MarkArray.MarkCount); + + // Reserve space for anchor offsets + long markAnchorOffsetsPos = writer.BaseStream.Position; + for (int i = 0; i < MarkArray.MarkCount; i++) + { + writer.WriteUInt16BigEndian(0); // MarkClass placeholder + writer.WriteUInt16BigEndian(0); // MarkAnchor offset placeholder + } + + // Write MarkRecords and Anchors + for (int i = 0; i < MarkArray.MarkCount; i++) + { + var record = MarkArray.Records[i]; + + // Update MarkClass + long currentPos = writer.BaseStream.Position; + writer.BaseStream.Seek(markAnchorOffsetsPos + (i * 4), System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(record.MarkClass); + writer.BaseStream.Seek(currentPos, System.IO.SeekOrigin.Begin); + + // Write Anchor + if (record.MarkAnchor != null) + { + long anchorStart = writer.BaseStream.Position; + ushort anchorOffset = (ushort)(anchorStart - markArrayStart); + + AnchorTableSerializer.Serialize(writer, record.MarkAnchor); + + // Update anchor offset + currentPos = writer.BaseStream.Position; + writer.BaseStream.Seek(markAnchorOffsetsPos + (i * 4) + 2, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(anchorOffset); + writer.BaseStream.Seek(currentPos, System.IO.SeekOrigin.Begin); + } + } + } + + // Update MarkArray offset + long resumePos = writer.BaseStream.Position; + writer.BaseStream.Seek(markArrayOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(markArrayOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + // Write BaseArray + long baseArrayStart = writer.BaseStream.Position; + ushort baseArrayOffset = (ushort)(baseArrayStart - subtableStart); + + if (BaseArray != null) + { + writer.WriteUInt16BigEndian(BaseArray.BaseCount); + + // Reserve space for anchor offsets + long baseAnchorOffsetsPos = writer.BaseStream.Position; + for (int i = 0; i < BaseArray.BaseCount; i++) + { + for (int j = 0; j < MarkClassCount; j++) + { + writer.WriteUInt16BigEndian(0); // Placeholder + } + } + + // Write BaseAnchors + for (int i = 0; i < BaseArray.BaseCount; i++) + { + var record = BaseArray.Records[i]; + + for (int j = 0; j < MarkClassCount; j++) + { + if (record.BaseAnchors != null && j < record.BaseAnchors.Length && record.BaseAnchors[j] != null) + { + long anchorStart = writer.BaseStream.Position; + ushort anchorOffset = (ushort)(anchorStart - baseArrayStart); + + AnchorTableSerializer.Serialize(writer, record.BaseAnchors[j]); + + // Update anchor offset + long currentPos = writer.BaseStream.Position; + writer.BaseStream.Seek(baseAnchorOffsetsPos + (i * MarkClassCount * 2) + (j * 2), System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(anchorOffset); + writer.BaseStream.Seek(currentPos, System.IO.SeekOrigin.Begin); + } + } + } + } + + // Update BaseArray offset + resumePos = writer.BaseStream.Position; + writer.BaseStream.Seek(baseArrayOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(baseArrayOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + // Write MarkCoverage table + if (MarkCoverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + resumePos = writer.BaseStream.Position; + + writer.BaseStream.Seek(markCoverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + MarkCoverage.Serialize(writer); + } + + // Write BaseCoverage table + if (BaseCoverage != null) + { + ushort coverageOffset = (ushort)(writer.BaseStream.Position - subtableStart); + resumePos = writer.BaseStream.Position; + + writer.BaseStream.Seek(baseCoverageOffsetPos, System.IO.SeekOrigin.Begin); + writer.WriteUInt16BigEndian(coverageOffset); + writer.BaseStream.Seek(resumePos, System.IO.SeekOrigin.Begin); + + BaseCoverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1Deserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1Deserializer.cs new file mode 100644 index 0000000000..2367fc68a1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/LookupType4/MarkToBaseSubTableFormat1Deserializer.cs @@ -0,0 +1,214 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Lookup Type 4 Deserializer + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4 +{ + /// + /// Deserializer for GPOS Lookup Type 4: MarkToBase Attachment Positioning + /// + internal class MarkToBaseSubTableFormat1Deserializer + { + private readonly FontsBinaryReader _reader; + + public MarkToBaseSubTableFormat1Deserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + /// + /// Deserializes a MarkToBase subtable from the current stream position. + /// + /// Absolute offset where this subtable starts + /// Deserialized MarkToBaseSubTableFormat1 + public MarkToBaseSubTableFormat1 Deserialize(long subtableStartOffset) + { + _reader.BaseStream.Seek(subtableStartOffset, SeekOrigin.Begin); + + var subtable = new MarkToBaseSubTableFormat1 + { + SubtableFormat = _reader.ReadUInt16BigEndian(), + MarkCoverageOffset = _reader.ReadUInt16BigEndian(), + BaseCoverageOffset = _reader.ReadUInt16BigEndian(), + MarkClassCount = _reader.ReadUInt16BigEndian(), + MarkArrayOffset = _reader.ReadUInt16BigEndian(), + BaseArrayOffset = _reader.ReadUInt16BigEndian() + }; + + // Read MarkCoverage table + if (subtable.MarkCoverageOffset > 0) + { + long coveragePos = subtableStartOffset + subtable.MarkCoverageOffset; + subtable.MarkCoverage = ReadCoverage(coveragePos); + } + + // Read BaseCoverage table + if (subtable.BaseCoverageOffset > 0) + { + long coveragePos = subtableStartOffset + subtable.BaseCoverageOffset; + subtable.BaseCoverage = ReadCoverage(coveragePos); + } + + // Read MarkArray + if (subtable.MarkArrayOffset > 0) + { + long markArrayPos = subtableStartOffset + subtable.MarkArrayOffset; + subtable.MarkArray = ReadMarkArray(markArrayPos); + } + + // Read BaseArray + if (subtable.BaseArrayOffset > 0) + { + long baseArrayPos = subtableStartOffset + subtable.BaseArrayOffset; + subtable.BaseArray = ReadBaseArray(baseArrayPos, subtable.MarkClassCount); + } + + return subtable; + } + + /// + /// Reads a Coverage table (Format 1 or 2) + /// + private CoverageTable ReadCoverage(long coverageOffset) + { + _reader.BaseStream.Seek(coverageOffset, SeekOrigin.Begin); + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + + if (coverageFormat == 1) + { + return new CoverageTableFormat1Deserializer(_reader).Deserialize(coverageOffset); + } + else if (coverageFormat == 2) + { + return new CoverageTableFormat2Deserializer(_reader).Deserialize(coverageOffset); + } + + return null; + } + + /// + /// Reads a MarkArray table + /// + private MarkArray ReadMarkArray(long markArrayStart) + { + _reader.BaseStream.Seek(markArrayStart, SeekOrigin.Begin); + + var markArray = new MarkArray + { + MarkCount = _reader.ReadUInt16BigEndian() + }; + + markArray.Records = new MarkRecord[markArray.MarkCount]; + + // Read MarkRecords + for (int i = 0; i < markArray.MarkCount; i++) + { + markArray.Records[i] = new MarkRecord + { + MarkClass = _reader.ReadUInt16BigEndian(), + MarkAnchorOffset = _reader.ReadUInt16BigEndian() + }; + } + + // Read Anchor tables for each mark + for (int i = 0; i < markArray.MarkCount; i++) + { + if (markArray.Records[i].MarkAnchorOffset > 0) + { + long anchorPos = markArrayStart + markArray.Records[i].MarkAnchorOffset; + markArray.Records[i].MarkAnchor = ReadAnchor(anchorPos); + } + } + + return markArray; + } + + /// + /// Reads a BaseArray table + /// + private BaseArray ReadBaseArray(long baseArrayStart, ushort markClassCount) + { + _reader.BaseStream.Seek(baseArrayStart, SeekOrigin.Begin); + + var baseArray = new BaseArray + { + BaseCount = _reader.ReadUInt16BigEndian() + }; + + baseArray.Records = new BaseRecord[baseArray.BaseCount]; + + // Read BaseRecords (offsets) + for (int i = 0; i < baseArray.BaseCount; i++) + { + baseArray.Records[i] = new BaseRecord + { + BaseAnchorOffsets = new ushort[markClassCount], + BaseAnchors = new AnchorTable[markClassCount] + }; + + // Read offsets for all mark classes + for (int classIndex = 0; classIndex < markClassCount; classIndex++) + { + baseArray.Records[i].BaseAnchorOffsets[classIndex] = _reader.ReadUInt16BigEndian(); + } + } + + // Read Anchor tables + for (int i = 0; i < baseArray.BaseCount; i++) + { + for (int classIndex = 0; classIndex < markClassCount; classIndex++) + { + ushort offset = baseArray.Records[i].BaseAnchorOffsets[classIndex]; + if (offset > 0) + { + long anchorPos = baseArrayStart + offset; + baseArray.Records[i].BaseAnchors[classIndex] = ReadAnchor(anchorPos); + } + } + } + + return baseArray; + } + + /// + /// Reads an Anchor table (Format 1, 2, or 3) + /// + private AnchorTable ReadAnchor(long anchorStart) + { + _reader.BaseStream.Seek(anchorStart, SeekOrigin.Begin); + + var anchor = new AnchorTable + { + AnchorFormat = _reader.ReadUInt16BigEndian(), + XCoordinate = _reader.ReadInt16BigEndian(), + YCoordinate = _reader.ReadInt16BigEndian() + }; + + if (anchor.AnchorFormat == 2) + { + // Format 2: includes anchor point index + anchor.AnchorPoint = _reader.ReadUInt16BigEndian(); + } + else if (anchor.AnchorFormat == 3) + { + // Format 3: includes device table offsets (we don't process them yet) + anchor.XDeviceOffset = _reader.ReadUInt16BigEndian(); + anchor.YDeviceOffset = _reader.ReadUInt16BigEndian(); + } + + return anchor; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/ValueRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/ValueRecord.cs new file mode 100644 index 0000000000..c454be28be --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Data/Lookups/ValueRecord.cs @@ -0,0 +1,184 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS ValueRecord implementation + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups +{ + /// + /// Represents a GPOS ValueRecord which defines positioning adjustments. + /// Fields present are determined by ValueFormat flags. + /// + public class ValueRecord + { + /// + /// Horizontal adjustment for placement (in font design units) + /// + public short XPlacement { get; set; } + + /// + /// Vertical adjustment for placement (in font design units) + /// + public short YPlacement { get; set; } + + /// + /// Horizontal adjustment for advance width (in font design units) + /// Used for kerning! + /// + public short XAdvance { get; set; } + + /// + /// Vertical adjustment for advance height (in font design units) + /// + public short YAdvance { get; set; } + + /// + /// Device table for XPlacement (not implemented yet) + /// + public ushort XPlacementDeviceOffset { get; set; } + + /// + /// Device table for YPlacement (not implemented yet) + /// + public ushort YPlacementDeviceOffset { get; set; } + + /// + /// Device table for XAdvance (not implemented yet) + /// + public ushort XAdvanceDeviceOffset { get; set; } + + /// + /// Device table for YAdvance (not implemented yet) + /// + public ushort YAdvanceDeviceOffset { get; set; } + + /// + /// Reads a ValueRecord from reader based on format flags + /// + internal static ValueRecord Read(FontsBinaryReader reader, ushort valueFormat) + { + var record = new ValueRecord(); + + if ((valueFormat & (ushort)ValueFormatFlags.XPlacement) != 0) + record.XPlacement = reader.ReadInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.YPlacement) != 0) + record.YPlacement = reader.ReadInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.XAdvance) != 0) + record.XAdvance = reader.ReadInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.YAdvance) != 0) + record.YAdvance = reader.ReadInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.XPlacementDevice) != 0) + record.XPlacementDeviceOffset = reader.ReadUInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.YPlacementDevice) != 0) + record.YPlacementDeviceOffset = reader.ReadUInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.XAdvanceDevice) != 0) + record.XAdvanceDeviceOffset = reader.ReadUInt16BigEndian(); + + if ((valueFormat & (ushort)ValueFormatFlags.YAdvanceDevice) != 0) + record.YAdvanceDeviceOffset = reader.ReadUInt16BigEndian(); + + return record; + } + + /// + /// Writes ValueRecord based on format flags + /// + internal void Write(FontsBinaryWriter writer, ushort valueFormat) + { + if ((valueFormat & (ushort)ValueFormatFlags.XPlacement) != 0) + writer.WriteInt16BigEndian(XPlacement); + + if ((valueFormat & (ushort)ValueFormatFlags.YPlacement) != 0) + writer.WriteInt16BigEndian(YPlacement); + + if ((valueFormat & (ushort)ValueFormatFlags.XAdvance) != 0) + writer.WriteInt16BigEndian(XAdvance); + + if ((valueFormat & (ushort)ValueFormatFlags.YAdvance) != 0) + writer.WriteInt16BigEndian(YAdvance); + + if ((valueFormat & (ushort)ValueFormatFlags.XPlacementDevice) != 0) + writer.WriteUInt16BigEndian(XPlacementDeviceOffset); + + if ((valueFormat & (ushort)ValueFormatFlags.YPlacementDevice) != 0) + writer.WriteUInt16BigEndian(YPlacementDeviceOffset); + + if ((valueFormat & (ushort)ValueFormatFlags.XAdvanceDevice) != 0) + writer.WriteUInt16BigEndian(XAdvanceDeviceOffset); + + if ((valueFormat & (ushort)ValueFormatFlags.YAdvanceDevice) != 0) + writer.WriteUInt16BigEndian(YAdvanceDeviceOffset); + } + + /// + /// Calculates ValueFormat flags needed for this record + /// + public ushort GetRequiredFormat() + { + ushort format = 0; + + if (XPlacement != 0) + format |= (ushort)ValueFormatFlags.XPlacement; + if (YPlacement != 0) + format |= (ushort)ValueFormatFlags.YPlacement; + if (XAdvance != 0) + format |= (ushort)ValueFormatFlags.XAdvance; + if (YAdvance != 0) + format |= (ushort)ValueFormatFlags.YAdvance; + if (XPlacementDeviceOffset != 0) + format |= (ushort)ValueFormatFlags.XPlacementDevice; + if (YPlacementDeviceOffset != 0) + format |= (ushort)ValueFormatFlags.YPlacementDevice; + if (XAdvanceDeviceOffset != 0) + format |= (ushort)ValueFormatFlags.XAdvanceDevice; + if (YAdvanceDeviceOffset != 0) + format |= (ushort)ValueFormatFlags.YAdvanceDevice; + + return format; + } + + /// + /// Checks if this record is empty (all zeros) + /// + public bool IsEmpty() + { + return XPlacement == 0 && YPlacement == 0 && + XAdvance == 0 && YAdvance == 0 && + XPlacementDeviceOffset == 0 && YPlacementDeviceOffset == 0 && + XAdvanceDeviceOffset == 0 && YAdvanceDeviceOffset == 0; + } + } + + /// + /// Flags indicating which fields are present in a ValueRecord + /// + [Flags] + public enum ValueFormatFlags : ushort + { + None = 0x0000, + XPlacement = 0x0001, + YPlacement = 0x0002, + XAdvance = 0x0004, + YAdvance = 0x0008, + XPlacementDevice = 0x0010, + YPlacementDevice = 0x0020, + XAdvanceDevice = 0x0040, + YAdvanceDevice = 0x0080 + // Reserved: 0xFF00 + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTable.cs new file mode 100644 index 0000000000..efca838409 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTable.cs @@ -0,0 +1,199 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS table implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Features; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using EPPlus.Fonts.OpenType.Utils; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos +{ + + /// + /// Represents the GPOS (Glyph Positioning) table. + /// Used for advanced typographic positioning including kerning, mark placement, etc. + /// + public class GposTable : FontTableBase + { + /// + /// Major version (should be 1) + /// + public ushort MajorVersion { get; set; } + + /// + /// Minor version (0 or 1) + /// + public ushort MinorVersion { get; set; } + + /// + /// Script list containing language systems + /// + public ScriptListTable ScriptList { get; set; } + + /// + /// Feature list containing typographic features (kern, mark, mkmk, etc) + /// + public FeatureListTable FeatureList { get; set; } + + /// + /// Lookup list containing positioning rules + /// + public LookupListTable LookupList { get; set; } + + /// + /// Feature variations table (GPOS 1.1) + /// + public uint FeatureVariationsOffset { get; set; } + + public override string Name => TableNames.Gpos; + + public override bool IsEssentialTable => false; + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + long tableStartOffset = writer.BaseStream.Position; + + // --- HEADER --- + writer.WriteUInt16BigEndian(this.MajorVersion); + writer.WriteUInt16BigEndian(this.MinorVersion); + + long scriptListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + long featureListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + long lookupListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + // GPOS 1.1 FeatureVariations (not implemented yet) + if (this.MajorVersion == 1 && this.MinorVersion == 1) + { + writer.WriteUInt32BigEndian(0); // FeatureVariations offset (0 = not present) + } + + // --- DATA --- + + // 1. ScriptList + if (this.ScriptList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, scriptListOffPos, this.ScriptList); + } + + // 2. FeatureList + if (this.FeatureList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, featureListOffPos, this.FeatureList); + } + + // 3. LookupList + if (this.LookupList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, lookupListOffPos, this.LookupList); + } + } + + internal override void Clear() + { + // TODO: Implement when needed for memory management + // This would clear internal caches/state if any + ScriptList = null; + FeatureList = null; + LookupList = null; + } + + /// Rewrites the GPOS table for subsetting. + /// Filters lookups, features, and scripts based on included glyphs. + /// + /// Subsetting context + /// Rewritten GPOS table, or null if no positioning data remains + internal GposTable Rewrite(FontSubsettingContext context) + { + var processor = context.GposProcessor; + if (processor == null) + return null; + + // 1. Rewrite LookupList first - creates lookup index mapping + LookupRewriteResult lookupResult = null; + if (this.LookupList != null) + { + lookupResult = RewriteLookupList(context, processor); + if (lookupResult == null || lookupResult.NewLookupList == null || lookupResult.NewLookupList.Lookups.Count == 0) + return null; // No positioning data remains + } + + // 2. Rewrite FeatureList - pass lookup index mapping, get feature index mapping back + FeatureRewriteResult featureResult = null; + if (this.FeatureList != null && lookupResult != null) + { + featureResult = this.FeatureList.Rewrite(context, lookupResult.OldToNewIndexMap); + if (featureResult == null || featureResult.NewFeatureList == null || featureResult.NewFeatureList.FeatureRecords.Count == 0) + return null; // No features remain + } + + // 3. Rewrite ScriptList - pass feature index mapping + ScriptListTable newScriptList = null; + if (this.ScriptList != null && featureResult != null) + { + newScriptList = this.ScriptList.Rewrite(context, featureResult.OldToNewIndexMap); + } + + // Create new GPOS table + var newGpos = new GposTable + { + MajorVersion = this.MajorVersion, + MinorVersion = this.MinorVersion, + ScriptList = newScriptList, + FeatureList = featureResult.NewFeatureList, + LookupList = lookupResult.NewLookupList + }; + + return newGpos; + } + + /// + /// Rewrites the LookupList by processing each lookup through its handler. + /// + private LookupRewriteResult RewriteLookupList(FontSubsettingContext context, GposSubsetProcessor processor) + { + if (this.LookupList == null) + return null; + + var newLookups = new List(); + var oldToNewIndexMap = new Dictionary(); + + for (int oldIndex = 0; oldIndex < this.LookupList.Lookups.Count; oldIndex++) + { + var lookup = this.LookupList.Lookups[oldIndex]; + var rewrittenLookup = processor.RewriteLookup(context, lookup); + + if (rewrittenLookup != null && rewrittenLookup.SubTables.Count > 0) + { + int newIndex = newLookups.Count; + oldToNewIndexMap[oldIndex] = newIndex; + newLookups.Add(rewrittenLookup); + } + } + + if (newLookups.Count == 0) + return null; + + return new LookupRewriteResult + { + NewLookupList = new LookupListTable { Lookups = newLookups }, + OldToNewIndexMap = oldToNewIndexMap + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTableLoader.cs new file mode 100644 index 0000000000..9f0df7753f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/GposTableLoader.cs @@ -0,0 +1,320 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/07/2026 EPPlus Software AB GPOS table loader + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Features; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos +{ + /// + /// Loader for GPOS (Glyph Positioning) table + /// + internal class GposTableLoader : TableLoader + { + public GposTableLoader(TableLoaderSettings settings) + : base(settings, TableNames.Gpos) + { + } + + protected override GposTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + var table = new GposTable(); + + // Read version + table.MajorVersion = _reader.ReadUInt16BigEndian(); + table.MinorVersion = _reader.ReadUInt16BigEndian(); + + if (table.MajorVersion != 1) + { + throw new NotSupportedException($"GPOS version {table.MajorVersion}.{table.MinorVersion} is not supported. Only version 1.x is supported."); + } + + // Read offsets + ushort scriptListOffset = _reader.ReadUInt16BigEndian(); + ushort featureListOffset = _reader.ReadUInt16BigEndian(); + ushort lookupListOffset = _reader.ReadUInt16BigEndian(); + + uint featureVariationsOffset = 0; + if (table.MinorVersion >= 1) + { + featureVariationsOffset = _reader.ReadUInt32BigEndian(); + table.FeatureVariationsOffset = featureVariationsOffset; + } + + long tableStart = _offset; + + // ✅ Use shared loaders from Common.Layout + if (scriptListOffset > 0) + { + _reader.BaseStream.Position = tableStart + scriptListOffset; + table.ScriptList = ScriptListTableLoader.Load(_reader, tableStart + scriptListOffset); + } + + if (featureListOffset > 0) + { + _reader.BaseStream.Position = tableStart + featureListOffset; + table.FeatureList = FeatureListTableLoader.Load(_reader, tableStart + featureListOffset); + } + + if (lookupListOffset > 0) + { + _reader.BaseStream.Position = tableStart + lookupListOffset; + table.LookupList = ReadLookupList(_reader, tableStart + lookupListOffset); + } + + // Note: FeatureVariations not implemented yet + // When implemented, read at tableStart + featureVariationsOffset + + return table; + } + + private LookupListTable ReadLookupList(FontsBinaryReader reader, long lookupListStart) + { + var lookupList = new LookupListTable(); + + ushort lookupCount = reader.ReadUInt16BigEndian(); + var lookupOffsets = new ushort[lookupCount]; + + for (int i = 0; i < lookupCount; i++) + { + lookupOffsets[i] = reader.ReadUInt16BigEndian(); + } + + lookupList.Lookups = new List(); + + for (int i = 0; i < lookupCount; i++) + { + if (lookupOffsets[i] == 0) + continue; + + reader.BaseStream.Position = lookupListStart + lookupOffsets[i]; + var lookup = ReadLookup(reader, lookupListStart + lookupOffsets[i]); + lookupList.Lookups.Add(lookup); + } + + return lookupList; + } + + private LookupTable ReadLookup(FontsBinaryReader reader, long lookupStart) + { + var lookup = new LookupTable(); + lookup.LookupType = reader.ReadUInt16BigEndian(); + lookup.LookupFlag = reader.ReadUInt16BigEndian(); + ushort subTableCount = reader.ReadUInt16BigEndian(); + + var subTableOffsets = new ushort[subTableCount]; + for (int i = 0; i < subTableCount; i++) + { + subTableOffsets[i] = reader.ReadUInt16BigEndian(); + } + + // Read MarkFilteringSet if present + if ((lookup.LookupFlag & 0x0010) != 0) + { + lookup.MarkFilteringSet = reader.ReadUInt16BigEndian(); + } + + lookup.SubTables = new List(); + for (int i = 0; i < subTableCount; i++) + { + if (subTableOffsets[i] == 0) + { + continue; + } + + reader.BaseStream.Position = lookupStart + subTableOffsets[i]; + var subTable = ReadSubTable(reader, lookup.LookupType, lookupStart + subTableOffsets[i]); + + if (subTable != null) + { + lookup.SubTables.Add(subTable); + } + } + + return lookup; + } + + private FontTableElement ReadSubTable(FontsBinaryReader reader, ushort lookupType, long subtableStart) + { + switch (lookupType) + { + case 1: + // Single adjustment positioning + return ReadSinglePosSubTable(reader, subtableStart); + + case 2: + // Pair adjustment positioning (KERNING!) + return ReadPairPosSubTable(reader, subtableStart); + + case 3: + // Cursive attachment positioning + // TODO: Implement when needed + return null; + + case 4: + // MarkToBase attachment positioning + return ReadMarkToBaseSubTable(reader, subtableStart); + + case 5: + // MarkToLigature attachment positioning + // TODO: Implement when needed + return null; + + case 6: + // MarkToMark attachment positioning + // TODO: Implement when needed + return null; + + case 7: + // Context positioning + // TODO: Implement when needed + return null; + + case 8: + // Chained context positioning + // TODO: Implement when needed + return null; + + case 9: + // Extension positioning + // TODO: Implement when needed + return ReadExtensionPosSubTable(reader, subtableStart); + + default: + // Unknown lookup type - skip + return null; + } + } + + private FontTableElement ReadPairPosSubTable(FontsBinaryReader reader, long subtableStart) + { + // ✅ FIX: Sätt position först! + reader.BaseStream.Position = subtableStart; + + ushort posFormat = reader.ReadUInt16BigEndian(); + + if (posFormat == 1) + { + reader.BaseStream.Position = subtableStart; // Reset för deserializer + return ReadPairPosFormat1(reader, subtableStart); + } + else if (posFormat == 2) + { + reader.BaseStream.Position = subtableStart; // Reset för deserializer + return ReadPairPosFormat2(reader, subtableStart); + } + else + { + throw new NotSupportedException($"PairPos format {posFormat} is not supported."); + } + } + + private PairPosSubTableFormat1 ReadPairPosFormat1(FontsBinaryReader reader, long subtableStart) + { + // ✅ Use the deserializer! + var deserializer = new PairPosSubTableFormat1Deserializer(reader); + return deserializer.Deserialize(subtableStart); + } + + private PairPosSubTableFormat2 ReadPairPosFormat2(FontsBinaryReader reader, long subtableStart) + { + var deserializer = new PairPosSubTableFormat2Deserializer(reader); + return deserializer.Deserialize(subtableStart); + } + + + private FontTableElement ReadSinglePosSubTable(FontsBinaryReader reader, long subtableStart) + { + // ✅ FIX: Sätt position FÖRST + reader.BaseStream.Position = subtableStart; + + // Read format to determine which deserializer to use + ushort posFormat = reader.ReadUInt16BigEndian(); + + // Reset for deserializer + reader.BaseStream.Position = subtableStart; + + if (posFormat == 1) + { + var deserializer = new SinglePosSubTableFormat1Deserializer(reader); + return deserializer.Deserialize(subtableStart); + } + else if (posFormat == 2) + { + var deserializer = new SinglePosSubTableFormat2Deserializer(reader); + return deserializer.Deserialize(subtableStart); + } + else + { + return null; + } + } + + private FontTableElement ReadMarkToBaseSubTable(FontsBinaryReader reader, long subtableStart) + { + // ✅ FIX: Sätt position INNAN du läser format + reader.BaseStream.Position = subtableStart; + + ushort posFormat = reader.ReadUInt16BigEndian(); + + // Reset to start for deserializer + reader.BaseStream.Position = subtableStart; + + if (posFormat == 1) + { + var deserializer = new MarkToBaseSubTableFormat1Deserializer(reader); + var result = deserializer.Deserialize(subtableStart); + return result; + } + else + { + return null; + } + } + + private FontTableElement ReadExtensionPosSubTable(FontsBinaryReader reader, long subtableStart) + { + reader.BaseStream.Position = subtableStart; + + ushort posFormat = reader.ReadUInt16BigEndian(); + + if (posFormat != 1) + { + return null; + } + + ushort extensionLookupType = reader.ReadUInt16BigEndian(); + uint extensionOffset = reader.ReadUInt32BigEndian(); + + + // ✅ CRITICAL: Prevent infinite recursion! + if (extensionLookupType == 9) + { + return null; + } + + long wrappedSubtableStart = subtableStart + extensionOffset; + + var result = ReadSubTable(reader, extensionLookupType, wrappedSubtableStart); + + return result; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/ExtensionPosHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/ExtensionPosHandler.cs new file mode 100644 index 0000000000..a56f1b02d1 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/ExtensionPosHandler.cs @@ -0,0 +1,85 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS lookup handler interface + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using EPPlus.Fonts.OpenType.Tables.Gpos.Handlers; +using System.Collections.Generic; + +internal class ExtensionPosHandler : IGposLookupHandler +{ + public ushort LookupType => 9; + + public void Discover(FontSubsettingContext context, LookupTable lookup, GposSubsetProcessor processor) + { + // Extension wraps another lookup - unwrap and delegate + foreach (var subtable in lookup.SubTables) + { + if (subtable is MarkToBaseSubTableFormat1) + { + // It's a wrapped MarkToBase - delegate to MarkToBase handler + var wrappedLookup = new LookupTable + { + LookupType = 4, + SubTables = new List { subtable } + }; + + var handler = processor.GetHandler(4); + if (handler != null) + { + handler.Discover(context, wrappedLookup, processor); + } + } + // Add cases for other wrapped types as needed + } + } + + public LookupTable Rewrite(FontSubsettingContext context, LookupTable lookup) + { + // Unwrap and delegate to the actual handler + if (lookup.SubTables.Count == 0) + return null; + + var firstSubtable = lookup.SubTables[0]; + + if (firstSubtable is MarkToBaseSubTableFormat1) + { + // Create a temporary Type 4 lookup + var wrappedLookup = new LookupTable + { + LookupType = 4, + LookupFlag = lookup.LookupFlag, + SubTables = lookup.SubTables + }; + + var handler = context.GposProcessor.GetHandler(4); + if (handler != null) + { + var rewritten = handler.Rewrite(context, wrappedLookup); + if (rewritten != null && rewritten.SubTables.Count > 0) + { + // Wrap back in Extension + return new LookupTable + { + LookupType = 9, + LookupFlag = lookup.LookupFlag, + SubTables = rewritten.SubTables + }; + } + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/IGposLookupHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/IGposLookupHandler.cs new file mode 100644 index 0000000000..97c1e82e2c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/IGposLookupHandler.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS lookup handler interface + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Handlers +{ + /// + /// Interface for GPOS lookup handlers. + /// Each lookup type (SinglePos, PairPos, MarkToBase, etc.) implements this interface. + /// + internal interface IGposLookupHandler + { + /// + /// The GPOS lookup type this handler supports (1-9). + /// + ushort LookupType { get; } + + /// + /// Phase 1: Discover additional glyphs that should be included in the subset. + /// For GPOS, this typically does nothing (positioning doesn't add glyphs). + /// + /// Subsetting context + /// The lookup to analyze + /// The GPOS processor (for recursive calls if needed) + void Discover(FontSubsettingContext context, LookupTable lookup, GposSubsetProcessor processor); + + /// + /// Phase 2: Rewrite the lookup with subsetted data and remapped glyph IDs. + /// + /// Subsetting context + /// The original lookup + /// Rewritten lookup, or null if no positioning data remains + LookupTable Rewrite(FontSubsettingContext context, LookupTable lookup); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/MarkToBaseHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/MarkToBaseHandler.cs new file mode 100644 index 0000000000..77a9eb3d98 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/MarkToBaseHandler.cs @@ -0,0 +1,264 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Type 4 (MarkToBase) handler + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Handlers +{ + /// + /// Handler for GPOS Lookup Type 4: MarkToBase Attachment Positioning. + /// Subsets MarkToBase lookups by filtering marks and bases, remapping IDs. + /// + internal class MarkToBaseHandler : IGposLookupHandler + { + public ushort LookupType => 4; + + /// + /// Phase 1: Discover. + /// MarkToBase doesn't add new glyphs - it only positions existing marks and bases. + /// + /// + /// Phase 1: Discover mark glyphs that should be included if their base glyphs are included. + /// This is CRITICAL because combining characters (U+0302, U+0309, etc.) map to mark glyphs + /// that might not be discovered by the normal cmap subsetting process. + /// We need to add ALL mark glyphs that can attach to ANY included base glyph. + /// + public void Discover(FontSubsettingContext context, LookupTable lookup, GposSubsetProcessor processor) + { + // Iterate through all subtables in this lookup + foreach (var subtableObj in lookup.SubTables) + { + if (subtableObj is MarkToBaseSubTableFormat1 subtable) + { + DiscoverMarkToBaseSubtable(context, subtable); + } + } + } + + /// + /// Discovers mark and base glyphs from a Mark-to-Base subtable. + /// Strategy: If ANY base glyph is included, include ALL marks that can attach to it. + /// This ensures combining characters work even if not explicitly in the subset string. + /// + private void DiscoverMarkToBaseSubtable(FontSubsettingContext context, MarkToBaseSubTableFormat1 subtable) + { + if (subtable.BaseCoverage == null || subtable.MarkCoverage == null) + return; + + // Check if any included base glyph exists in this subtable + bool hasIncludedBase = false; + + // Iterate through all potentially included glyphs + foreach (ushort baseGlyph in context.IncludedGlyphs) + { + // Check if this base glyph is in the BaseCoverage + int baseIndex = subtable.BaseCoverage.GetGlyphIndex(baseGlyph); + if (baseIndex >= 0) + { + hasIncludedBase = true; + break; + } + } + + // If we have at least one included base, include ALL marks from this subtable + if (hasIncludedBase) + { + // MarkCoverage.GetGlyphIndex() returns -1 if glyph is not covered + // We need to iterate through all possible glyph IDs to find covered marks + for (ushort markGlyph = 0; markGlyph < 65535; markGlyph++) + { + int markIndex = subtable.MarkCoverage.GetGlyphIndex(markGlyph); + if (markIndex >= 0) + { + // This is a mark glyph - add it to included glyphs + context.IncludedGlyphs.Add(markGlyph); + } + } + } + } + + /// + /// Phase 2: Rewrite the lookup with subsetted data and remapped glyph IDs. + /// + public LookupTable Rewrite(FontSubsettingContext context, LookupTable lookup) + { + var newLookup = new LookupTable + { + LookupType = lookup.LookupType, + LookupFlag = lookup.LookupFlag, + MarkFilteringSet = lookup.MarkFilteringSet, + SubTables = new List() + }; + + foreach (var subtable in lookup.SubTables) + { + if (subtable is MarkToBaseSubTableFormat1 format1) + { + var rewritten = RewriteFormat1(context, format1); + if (rewritten != null) + { + newLookup.SubTables.Add(rewritten); + } + } + } + + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + + /// + /// Rewrites a MarkToBase Format 1 subtable. + /// + private MarkToBaseSubTableFormat1 RewriteFormat1(FontSubsettingContext context, MarkToBaseSubTableFormat1 original) + { + // Filter mark coverage + var newMarkCoverage = FilterCoverage(context, original.MarkCoverage); + if (newMarkCoverage == null) + return null; // No marks remain + + // Filter base coverage + var newBaseCoverage = FilterCoverage(context, original.BaseCoverage); + if (newBaseCoverage == null) + return null; // No bases remain + + // Rebuild MarkArray + var newMarkArray = FilterMarkArray(context, original); + if (newMarkArray == null || newMarkArray.MarkCount == 0) + return null; + + // Rebuild BaseArray + var newBaseArray = FilterBaseArray(context, original); + if (newBaseArray == null || newBaseArray.BaseCount == 0) + return null; + + var rewritten = new MarkToBaseSubTableFormat1 + { + SubtableFormat = 1, + MarkClassCount = original.MarkClassCount, + MarkCoverage = newMarkCoverage, + BaseCoverage = newBaseCoverage, + MarkArray = newMarkArray, + BaseArray = newBaseArray + }; + + return rewritten; + } + + /// + /// Filters MarkArray to only include marks in the subset. + /// + private MarkArray FilterMarkArray(FontSubsettingContext context, MarkToBaseSubTableFormat1 original) + { + var includedRecords = new List(); + + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + int coverageIndex = original.MarkCoverage.GetGlyphIndex(oldGlyphId); + if (coverageIndex >= 0 && coverageIndex < original.MarkArray.MarkCount) + { + // Check if this mark is included in subset + if (context.OldToNewGlyphId.ContainsKey(oldGlyphId)) + { + includedRecords.Add(original.MarkArray.Records[coverageIndex]); + } + } + } + + if (includedRecords.Count == 0) + return null; + + return new MarkArray + { + MarkCount = (ushort)includedRecords.Count, + Records = includedRecords.ToArray() + }; + } + + /// + /// Filters BaseArray to only include bases in the subset. + /// + private BaseArray FilterBaseArray(FontSubsettingContext context, MarkToBaseSubTableFormat1 original) + { + var includedRecords = new List(); + + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + int coverageIndex = original.BaseCoverage.GetGlyphIndex(oldGlyphId); + if (coverageIndex >= 0 && coverageIndex < original.BaseArray.BaseCount) + { + // Check if this base is included in subset + if (context.OldToNewGlyphId.ContainsKey(oldGlyphId)) + { + includedRecords.Add(original.BaseArray.Records[coverageIndex]); + } + } + } + + if (includedRecords.Count == 0) + return null; + + return new BaseArray + { + BaseCount = (ushort)includedRecords.Count, + Records = includedRecords.ToArray() + }; + } + + /// + /// Filters a coverage table to only included glyphs and remaps IDs. + /// + private CoverageTable FilterCoverage(FontSubsettingContext context, CoverageTable original) + { + if (original == null) + return null; + + var includedGlyphs = new List(); + + // Iterate through all glyphs in original coverage + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + if (original.GetGlyphIndex(oldGlyphId) >= 0) + { + // This glyph is in coverage - check if included in subset + if (context.OldToNewGlyphId.TryGetValue(oldGlyphId, out ushort newGlyphId)) + { + includedGlyphs.Add(newGlyphId); + } + } + } + + if (includedGlyphs.Count == 0) + return null; + + return CreateCoverageFromGlyphs(includedGlyphs); + } + + /// + /// Creates a Coverage Format 1 table from a list of glyph IDs. + /// + private CoverageTable CreateCoverageFromGlyphs(List glyphIds) + { + // Sort glyphs for Coverage Format 1 + glyphIds.Sort(); + + return new CoverageTableFormat1 + { + CoverageFormat = 1, + GlyphCount = (ushort)glyphIds.Count, + GlyphArray = glyphIds.ToArray() + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/PairPosHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/PairPosHandler.cs new file mode 100644 index 0000000000..7a6e5794b2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/PairPosHandler.cs @@ -0,0 +1,309 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Type 2 (PairPos) handler + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Handlers +{ + /// + /// Handler for GPOS Lookup Type 2: Pair Adjustment Positioning (Kerning). + /// Subsets PairPos lookups by filtering glyph pairs and remapping IDs. + /// + internal class PairPosHandler : IGposLookupHandler + { + private class GlyphMapping + { + public ushort OldGlyphId { get; set; } + public ushort NewGlyphId { get; set; } + public int OldCoverageIndex { get; set; } + } + + public ushort LookupType => 2; + + /// + /// Phase 1: Discover. + /// PairPos doesn't add new glyphs - it only positions existing pairs. + /// + public void Discover(FontSubsettingContext context, LookupTable lookup, GposSubsetProcessor processor) + { + // No-op: positioning doesn't require additional glyphs + } + + /// + /// Phase 2: Rewrite the lookup with subsetted data and remapped glyph IDs. + /// + public LookupTable Rewrite(FontSubsettingContext context, LookupTable lookup) + { + var newLookup = new LookupTable + { + LookupType = lookup.LookupType, + LookupFlag = lookup.LookupFlag, + MarkFilteringSet = lookup.MarkFilteringSet, + SubTables = new List() + }; + + foreach (var subtable in lookup.SubTables) + { + GposSubTableBase rewritten = null; + + if (subtable is PairPosSubTableFormat1 format1) + { + rewritten = RewriteFormat1(context, format1); + } + else if (subtable is PairPosSubTableFormat2 format2) // ← Aktivera! + { + rewritten = RewriteFormat2(context, format2); + } + + if (rewritten != null) + { + newLookup.SubTables.Add(rewritten); + } + } + + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + + /// + /// Rewrites a PairPos Format 1 subtable. + /// + private PairPosSubTableFormat1 RewriteFormat1(FontSubsettingContext context, PairPosSubTableFormat1 original) + { + // Build list of included first glyphs with their coverage indices + var includedGlyphs = new List(); + + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + int coverageIndex = original.Coverage.GetGlyphIndex(oldGlyphId); + if (coverageIndex >= 0 && coverageIndex < original.PairSets.Count) + { + if (context.OldToNewGlyphId.TryGetValue(oldGlyphId, out ushort newGlyphId)) + { + includedGlyphs.Add(new GlyphMapping + { + OldGlyphId = oldGlyphId, + NewGlyphId = newGlyphId, + OldCoverageIndex = coverageIndex + }); + } + } + } + + if (includedGlyphs.Count == 0) + return null; + + // Sort by NEW glyph ID (for coverage) + includedGlyphs.Sort((a, b) => a.NewGlyphId.CompareTo(b.NewGlyphId)); + + // Build PairSets in new coverage order + var newPairSets = new List(); + var newGlyphIds = new List(); + + foreach (var mapping in includedGlyphs) + { + var oldPairSet = original.PairSets[mapping.OldCoverageIndex]; + if (oldPairSet != null) + { + var newPairSet = FilterPairSet(context, oldPairSet); + + if (newPairSet != null && newPairSet.PairValueRecords.Count > 0) + { + newGlyphIds.Add(mapping.NewGlyphId); + newPairSets.Add(newPairSet); + } + } + } + + if (newPairSets.Count == 0) + return null; + + // Create new coverage with sorted glyph IDs + var newCoverage = new CoverageTableFormat1 + { + CoverageFormat = 1, + GlyphCount = (ushort)newGlyphIds.Count, + GlyphArray = newGlyphIds.ToArray() + }; + + var rewritten = new PairPosSubTableFormat1 + { + SubtableFormat = 1, + ValueFormat1 = original.ValueFormat1, + ValueFormat2 = original.ValueFormat2, + Coverage = newCoverage, + PairSets = newPairSets + }; + + return rewritten; + } + + /// + /// Rewrites a PairPos Format 2 subtable by expanding class-based kerning to Format 1. + /// This simplifies subsetting and ensures compatibility. + /// + private PairPosSubTableFormat1 RewriteFormat2(FontSubsettingContext context, PairPosSubTableFormat2 original) + { + // Strategy: Expand class matrix to individual pairs (Format 1) + // This is simpler than subsetting the class definitions and matrix + + // Build map of first glyphs that are both: + // 1. In the original coverage + // 2. In our subset + var firstGlyphMappings = new List(); + + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + // Must be in coverage + int coverageIndex = original.Coverage.GetGlyphIndex(oldGlyphId); + if (coverageIndex < 0) + continue; + + // Must be in subset + if (!context.OldToNewGlyphId.TryGetValue(oldGlyphId, out ushort newGlyphId)) + continue; + + firstGlyphMappings.Add(new GlyphMapping + { + OldGlyphId = oldGlyphId, + NewGlyphId = newGlyphId, + OldCoverageIndex = -1 // Not used for Format 2 + }); + } + + if (firstGlyphMappings.Count == 0) + return null; + + // Sort by NEW glyph ID for coverage + firstGlyphMappings.Sort((a, b) => a.NewGlyphId.CompareTo(b.NewGlyphId)); + + // Build PairSets by expanding class matrix + var newPairSets = new List(); + var newCoverageGlyphs = new List(); + + foreach (var firstMapping in firstGlyphMappings) + { + // Get class for first glyph + int class1 = original.ClassDef1.GetClass(firstMapping.OldGlyphId); + if (class1 < 0 || class1 >= original.Class1Count) + continue; + + // Collect all pairs for this first glyph + var pairRecords = new List(); + + // Check all possible second glyphs in our subset + foreach (var oldSecondGlyph in context.IncludedGlyphs) + { + // Skip if same glyph + if (oldSecondGlyph == firstMapping.OldGlyphId) + continue; + + // Get class for second glyph + int class2 = original.ClassDef2.GetClass(oldSecondGlyph); + if (class2 < 0 || class2 >= original.Class2Count) + continue; + + // Look up in class matrix + var record = original.ClassMatrix[class1, class2]; + if (record == null) + continue; + + // Skip if no actual adjustment + bool hasValue1 = record.Value1 != null && record.Value1.XAdvance != 0; + bool hasValue2 = record.Value2 != null && record.Value2.XAdvance != 0; + + if (!hasValue1 && !hasValue2) + continue; + + // Get remapped second glyph ID + if (!context.OldToNewGlyphId.TryGetValue(oldSecondGlyph, out ushort newSecondGlyph)) + continue; + + // Add pair with remapped ID + pairRecords.Add(new PairValueRecord + { + SecondGlyph = newSecondGlyph, + Value1 = record.Value1, + Value2 = record.Value2 + }); + } + + // Only include if we found pairs + if (pairRecords.Count > 0) + { + newCoverageGlyphs.Add(firstMapping.NewGlyphId); + newPairSets.Add(new PairSet + { + PairValueRecords = pairRecords + }); + } + } + + if (newPairSets.Count == 0) + return null; + + // Create new coverage + var newCoverage = new CoverageTableFormat1 + { + CoverageFormat = 1, + GlyphCount = (ushort)newCoverageGlyphs.Count, + GlyphArray = newCoverageGlyphs.ToArray() + }; + + // Return as Format 1 (expanded from class-based) + return new PairPosSubTableFormat1 + { + SubtableFormat = 1, + ValueFormat1 = original.ValueFormat1, + ValueFormat2 = original.ValueFormat2, + Coverage = newCoverage, + PairSets = newPairSets + }; + } + + /// + /// Filters a PairSet to only include pairs where second glyph is in subset. + /// Remaps second glyph IDs. + /// + private PairSet FilterPairSet(FontSubsettingContext context, PairSet original) + { + var newRecords = new List(); + + foreach (var record in original.PairValueRecords) + { + // Check if second glyph is included in subset + if (context.OldToNewGlyphId.TryGetValue(record.SecondGlyph, out ushort newSecondGlyph)) + { + var newRecord = new PairValueRecord + { + SecondGlyph = newSecondGlyph, // Remapped ID + Value1 = record.Value1, + Value2 = record.Value2 + }; + newRecords.Add(newRecord); + } + } + + if (newRecords.Count == 0) + return null; + + return new PairSet + { + PairValueRecords = newRecords + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/SinglePosHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/SinglePosHandler.cs new file mode 100644 index 0000000000..289ab26903 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gpos/Handlers/SinglePosHandler.cs @@ -0,0 +1,183 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB GPOS Type 1 (SinglePos) handler + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Handlers +{ + /// + /// Handler for GPOS Lookup Type 1: Single Adjustment Positioning. + /// Subsets SinglePos lookups by filtering glyphs and remapping IDs. + /// + internal class SinglePosHandler : IGposLookupHandler + { + public ushort LookupType => 1; + + /// + /// Phase 1: Discover. + /// SinglePos doesn't add new glyphs - it only positions existing ones. + /// + public void Discover(FontSubsettingContext context, LookupTable lookup, GposSubsetProcessor processor) + { + // No-op: positioning doesn't require additional glyphs + } + + /// + /// Phase 2: Rewrite the lookup with subsetted data and remapped glyph IDs. + /// + public LookupTable Rewrite(FontSubsettingContext context, LookupTable lookup) + { + var newLookup = new LookupTable + { + LookupType = lookup.LookupType, + LookupFlag = lookup.LookupFlag, + MarkFilteringSet = lookup.MarkFilteringSet, + SubTables = new List() + }; + + foreach (var subtable in lookup.SubTables) + { + GposSubTableBase rewritten = null; + + if (subtable is SinglePosSubTableFormat1 format1) + { + rewritten = RewriteFormat1(context, format1); + } + else if (subtable is SinglePosSubTableFormat2 format2) + { + rewritten = RewriteFormat2(context, format2); + } + + if (rewritten != null) + { + newLookup.SubTables.Add(rewritten); + } + } + + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + + /// + /// Rewrites a SinglePos Format 1 subtable. + /// + private SinglePosSubTableFormat1 RewriteFormat1(FontSubsettingContext context, SinglePosSubTableFormat1 original) + { + // Filter coverage to only included glyphs + var newCoverage = FilterCoverage(context, original.Coverage); + + if (newCoverage == null) + return null; // No glyphs remain + + var rewritten = new SinglePosSubTableFormat1 + { + SubtableFormat = 1, + ValueFormat = original.ValueFormat, + Value = original.Value, // Same adjustment for all glyphs + Coverage = newCoverage + }; + + return rewritten; + } + + /// + /// Rewrites a SinglePos Format 2 subtable. + /// + private SinglePosSubTableFormat2 RewriteFormat2(FontSubsettingContext context, SinglePosSubTableFormat2 original) + { + // Get list of included glyphs in coverage order + var includedGlyphs = new List(); + var includedValues = new List(); + + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + int coverageIndex = original.Coverage.GetGlyphIndex(oldGlyphId); + if (coverageIndex >= 0 && coverageIndex < original.Values.Length) + { + // Check if this glyph is included in subset + if (context.OldToNewGlyphId.ContainsKey(oldGlyphId)) + { + includedGlyphs.Add(context.OldToNewGlyphId[oldGlyphId]); // New ID + includedValues.Add(original.Values[coverageIndex]); + } + } + } + + if (includedGlyphs.Count == 0) + return null; // No glyphs remain + + // Create new coverage with remapped glyph IDs + var newCoverage = CreateCoverageFromGlyphs(includedGlyphs); + + var rewritten = new SinglePosSubTableFormat2 + { + SubtableFormat = 2, + ValueFormat = original.ValueFormat, + ValueCount = (ushort)includedValues.Count, + Values = includedValues.ToArray(), + Coverage = newCoverage + }; + + return rewritten; + } + + /// + /// Filters a coverage table to only included glyphs and remaps IDs. + /// + private CoverageTable FilterCoverage(FontSubsettingContext context, CoverageTable original) + { + if (original == null) + return null; + + var includedGlyphs = new List(); + + // Iterate through all glyphs in original coverage + for (ushort oldGlyphId = 0; oldGlyphId < 65535; oldGlyphId++) + { + if (original.GetGlyphIndex(oldGlyphId) >= 0) + { + // This glyph is in coverage - check if included in subset + if (context.OldToNewGlyphId.TryGetValue(oldGlyphId, out ushort newGlyphId)) + { + includedGlyphs.Add(newGlyphId); + } + } + } + + if (includedGlyphs.Count == 0) + return null; + + return CreateCoverageFromGlyphs(includedGlyphs); + } + + /// + /// Creates a Coverage Format 1 table from a list of glyph IDs. + /// + private CoverageTable CreateCoverageFromGlyphs(List glyphIds) + { + // Sort glyphs for Coverage Format 1 + glyphIds.Sort(); + + return new CoverageTableFormat1 + { + CoverageFormat = 1, + GlyphCount = (ushort)glyphIds.Count, + GlyphArray = glyphIds.ToArray() + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/AnchorTableSerializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/AnchorTableSerializer.cs new file mode 100644 index 0000000000..21f26e96e9 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/AnchorTableSerializer.cs @@ -0,0 +1,54 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB AnchorTable serialization + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups +{ + /// + /// Static helper for serializing AnchorTable structures. + /// Used by MarkToBase, MarkToLigature, MarkToMark, and Cursive lookups. + /// + internal static class AnchorTableSerializer + { + /// + /// Serializes an AnchorTable (Format 1, 2, or 3). + /// + /// Binary writer + /// Anchor table to serialize + public static void Serialize(FontsBinaryWriter writer, AnchorTable anchor) + { + if (anchor == null) + return; + + // Write format + writer.WriteUInt16BigEndian(anchor.AnchorFormat); + + // Write X and Y coordinates (all formats) + writer.WriteInt16BigEndian(anchor.XCoordinate); + writer.WriteInt16BigEndian(anchor.YCoordinate); + + // Format-specific fields + if (anchor.AnchorFormat == 2) + { + // Format 2: Anchor point index + writer.WriteUInt16BigEndian(anchor.AnchorPoint); + } + else if (anchor.AnchorFormat == 3) + { + // Format 3: Device table offsets + // We don't implement device tables yet, so write zeros + writer.WriteUInt16BigEndian(0); // XDeviceOffset + writer.WriteUInt16BigEndian(0); // YDeviceOffset + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ChainingContextualSubstFormat3.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ChainingContextualSubstFormat3.cs new file mode 100644 index 0000000000..aa6e4b9e17 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ChainingContextualSubstFormat3.cs @@ -0,0 +1,139 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + public class ChainingContextualSubstFormat3 : FontTableElement + { + public List BacktrackCoverages { get; set; } = new(); + public List InputCoverages { get; set; } = new(); + public List LookaheadCoverages { get; set; } = new(); + public List SubstLookupRecords { get; set; } = new(); + + internal override void Serialize(FontsBinaryWriter writer) + { + long startPos = writer.BaseStream.Position; + + // 1. Format 3 + writer.WriteUInt16BigEndian(3); + + // 2. Backtrack Coverage + writer.WriteUInt16BigEndian((ushort)BacktrackCoverages.Count); + long backtrackOffsetsStart = writer.BaseStream.Position; + for (int i = 0; i < BacktrackCoverages.Count; i++) writer.WriteUInt16BigEndian(0); + + // 3. Input Coverage + writer.WriteUInt16BigEndian((ushort)InputCoverages.Count); + long inputOffsetsStart = writer.BaseStream.Position; + for (int i = 0; i < InputCoverages.Count; i++) writer.WriteUInt16BigEndian(0); + + // 4. Lookahead Coverage + writer.WriteUInt16BigEndian((ushort)LookaheadCoverages.Count); + long lookaheadOffsetsStart = writer.BaseStream.Position; + for (int i = 0; i < LookaheadCoverages.Count; i++) writer.WriteUInt16BigEndian(0); + + // 5. SubstLookupRecords + writer.WriteUInt16BigEndian((ushort)SubstLookupRecords.Count); + foreach (var record in SubstLookupRecords) + { + writer.WriteUInt16BigEndian(record.SequenceIndex); + writer.WriteUInt16BigEndian(record.LookupListIndex); + } + + // --- Skriv ut faktiska Coverage-tabeller och backfilla offsets --- + + SerializeCoverageList(writer, BacktrackCoverages, startPos, backtrackOffsetsStart); + SerializeCoverageList(writer, InputCoverages, startPos, inputOffsetsStart); + SerializeCoverageList(writer, LookaheadCoverages, startPos, lookaheadOffsetsStart); + } + + private void SerializeCoverageList(FontsBinaryWriter writer, List coverages, long subTableStart, long offsetArrayStart) + { + for (int i = 0; i < coverages.Count; i++) + { + long currentPos = writer.BaseStream.Position; + long offsetInArray = offsetArrayStart + (i * 2); + + this.WriteRelativeOffset(writer, subTableStart, offsetInArray); + coverages[i].Serialize(writer); + } + } + + internal ChainingContextualSubstFormat3 Rewrite(FontSubsettingContext context) + { + var newTable = new ChainingContextualSubstFormat3(); + + // 1. Mappa om listorna. + // Vår hjälpmetod RewriteCoverageList returnerar nu en tom lista istället för null + // om originalet var tomt/null, för att tillfredsställa Writer-koden. + newTable.BacktrackCoverages = RewriteCoverageList(this.BacktrackCoverages, context) ?? new List(); + newTable.InputCoverages = RewriteCoverageList(this.InputCoverages, context); + newTable.LookaheadCoverages = RewriteCoverageList(this.LookaheadCoverages, context) ?? new List(); + + // 2. Validering: Input MÅSTE finnas för att regeln ska vara giltig. + if (newTable.InputCoverages == null || newTable.InputCoverages.Count == 0) return null; + + // 3. Kopiera records + if (this.SubstLookupRecords != null) + { + newTable.SubstLookupRecords = new List(this.SubstLookupRecords); + } + else + { + newTable.SubstLookupRecords = new List(); + } + + return newTable; + } + + private List RewriteCoverageList(List oldCoverages, FontSubsettingContext context) + { + // Om originalet var null eller tomt, returnera en tom lista (inte null) + if (oldCoverages == null || oldCoverages.Count == 0) + { + return new List(); + } + + var newCoverages = new List(); + foreach (var cov in oldCoverages) + { + var oldGids = cov.GetCoveredGlyphs(); + var validNewGids = new List(); + + foreach (var oldGid in oldGids) + { + if (context.OldToNewGlyphId.TryGetValue(oldGid, out ushort newGid)) + { + validNewGids.Add(newGid); + } + } + + // Om en hel position i sekvensen försvinner, blir regeln ogiltig + if (validNewGids.Count == 0) return null; + + validNewGids.Sort(); + newCoverages.Add(new CoverageTableFormat1 + { + GlyphArray = validNewGids.ToArray(), + GlyphCount = (ushort)validNewGids.Count + }); + } + return newCoverages; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ExtensionSubstSubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ExtensionSubstSubTable.cs new file mode 100644 index 0000000000..d6e06ed3bd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ExtensionSubstSubTable.cs @@ -0,0 +1,52 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 12/21/2025 EPPlus Software AB Refactor: Inherit from ExtensionSubTableBase + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents an Extension Substitution subtable (Lookup Type 7). + /// This is used to reference subtables that exceed the 16-bit offset limit. + /// + public class ExtensionSubstSubTable : ExtensionSubTableBase + { + /// + /// Rewrites the extension by rewriting the inner subtable. + /// + internal ExtensionSubstSubTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + if (ExtendedSubTable == null) return null; + + // We delegate the rewrite to the specific type of the inner table + FontTableElement rewrittenInner = null; + + if (ExtendedSubTable is SingleSubstSubTable single) + rewrittenInner = single.Rewrite(context, oldLookup); + else if (ExtendedSubTable is LigatureSubstSubTable ligature) + rewrittenInner = ligature.Rewrite(context, oldLookup); + else if (ExtendedSubTable is ChainingContextualSubstFormat3 contextual) + rewrittenInner = contextual.Rewrite(context); + // Add more types here as they are implemented + + if (rewrittenInner == null) return null; + + return new ExtensionSubstSubTable + { + ExtensionLookupType = this.ExtensionLookupType, + ExtendedSubTable = rewrittenInner + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/GsubRewriteEntry.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/GsubRewriteEntry.cs new file mode 100644 index 0000000000..90bea3f64e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/GsubRewriteEntry.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// En hjälpstruktur för att hålla mappningen mellan gamla och nya Glyph IDs + /// under omskrivningen (Rewrite) av GSUB-tabeller. + /// + internal struct GsubRewriteEntry + { + /// + /// Det nya Glyph ID:t för källtecknet (Input). + /// + public ushort NewInput; + + /// + /// Det nya Glyph ID:t för ersättningstecknet (Output/Substitute). + /// + public ushort NewOutput; + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSetTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSetTable.cs new file mode 100644 index 0000000000..64d09bcb27 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSetTable.cs @@ -0,0 +1,157 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a Ligature Set table, which contains a list of ligatures + /// beginning with a specific first glyph (the base glyph). + /// + public class LigatureSetTable : FontTableElement + { + /// + /// Array of Ligature tables, each corresponding to a substitution sequence + /// starting with the BaseGlyph (defined by the Coverage table). + /// + public List Ligatures { get; set; } = new List(); + + /// + /// Filters and remaps all contained LigatureTable entries. + /// + /// The glyph ID mapping. + /// A new, filtered LigatureSetTable containing only valid ligatures. + internal LigatureSetTable CreateSubset(Dictionary oldToNewGlyphId) + { + LigatureSetTable newSet = new LigatureSetTable(); + + foreach (var oldLigature in this.Ligatures) + { + // 1. Try to map the target glyph (e.g., the "fi" ligature glyph) + if (!oldToNewGlyphId.TryGetValue(oldLigature.LigatureGlyph, out ushort newTargetGid)) + { + continue; // Target glyph is not part of our subset + } + + // 2. Try to map all subsequent components (e.g., the "i" in "f" + "i") + bool allComponentsMapped = true; + List newComponents = new List(); + + foreach (var oldCompGid in oldLigature.Components) + { + if (oldToNewGlyphId.TryGetValue(oldCompGid, out ushort newCompGid)) + { + newComponents.Add(newCompGid); + } + else + { + allComponentsMapped = false; + break; // A required component is missing; the ligature cannot be formed + } + } + + // 3. If all parts exist in the subset, create a NEW Ligature instance + if (allComponentsMapped) + { + newSet.Ligatures.Add(new LigatureTable + { + LigatureGlyph = newTargetGid, + Components = newComponents.ToArray() + }); + } + } + + return newSet; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + // Write LigatureCount + writer.WriteUInt16BigEndian((ushort)this.Ligatures.Count); + + // 1. Calculate and Write Offsets + // Start offset is after LigatureCount (2 bytes) + all offset entries (2 bytes per ligature) + int currentOffset = (this.Ligatures.Count * sizeof(ushort)) + sizeof(ushort); + + foreach (var ligature in this.Ligatures) + { + writer.WriteUInt16BigEndian((ushort)currentOffset); + + // Calculate size of this LigatureTable to find the next offset: + // 2 bytes (LigatureGlyph) + 2 bytes (ComponentCount) + (Components.Length * 2 bytes) + currentOffset += (sizeof(ushort) * 2) + (ligature.Components.Length * sizeof(ushort)); + } + + // 2. Write actual LigatureTable data + foreach (var ligature in this.Ligatures) + { + ligature.Serialize(writer); + } + } + + /// + /// Rewrites the ligature set based on the subsetting context. + /// + internal LigatureSetTable Rewrite(FontSubsettingContext context) + { + LigatureSetTable newSet = new LigatureSetTable(); + + foreach (LigatureTable oldLig in this.Ligatures) + { + // Check if ligature output glyph is in subset + if (!context.OldToNewGlyphId.TryGetValue(oldLig.LigatureGlyph, out ushort newTargetGid)) + { + continue; + } + + var newComponents = new List(); + bool allComponentsMapped = true; + int baseCharacterCount = 0; // Track how many base characters we found + + + foreach (var oldCompGid in oldLig.Components) + { + + baseCharacterCount++; + + if (context.OldToNewGlyphId.TryGetValue(oldCompGid, out ushort newCompGid)) + { + newComponents.Add(newCompGid); + } + else + { + allComponentsMapped = false; + break; + } + } + + + // ✅ CRITICAL: Only add ligature if: + // 1. All required components mapped successfully + // 2. We have at least one base character component + // (prevents ligatures with only ligature-components like [442, 1215]) + if (allComponentsMapped && baseCharacterCount > 0) + { + newSet.Ligatures.Add(new LigatureTable + { + LigatureGlyph = newTargetGid, + Components = newComponents.ToArray() + }); + } + } + + return newSet.Ligatures.Count > 0 ? newSet : null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSubstSubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSubstSubTable.cs new file mode 100644 index 0000000000..47f11431e6 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureSubstSubTable.cs @@ -0,0 +1,211 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a Ligature Substitution Subtable (Lookup Type 4, Format 1). + /// This table maps a Base Glyph (via the Coverage table) to a LigatureSetTable. + /// + public class LigatureSubstSubTable : FontTableElement + { + /// + /// Gets or sets the format identifier for the subtable (should be 1). + /// + public ushort SubtableFormat { get; set; } + + /// + /// Gets or sets the Coverage table which defines the set of initial glyphs (Base Glyphs) + /// that start the ligature sequence. + /// + public CoverageTable Coverage { get; set; } + + /// + /// Gets or sets a dictionary mapping the Base Glyph ID (from the Coverage table) + /// to the corresponding Ligature Set. + /// + public Dictionary LigatureSets { get; set; } = new Dictionary(); + + internal override void Serialize(FontsBinaryWriter writer) + { + // 1. Store start position for relative offset calculations + long subTableStart = writer.BaseStream.Position; + + // 2. Write Header + writer.WriteUInt16BigEndian(this.SubtableFormat); // Usually 1 + + // 3. Placeholder for CoverageOffset + long covOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); + + // 4. Write number of LigatureSets + writer.WriteUInt16BigEndian((ushort)this.LigatureSets.Count); + + // 5. Write placeholders for each LigatureSetOffset + // These must be written in the exact same order as the glyphs in the CoverageTable + List ligSetOffsetPositions = new List(); + for (int i = 0; i < this.LigatureSets.Count; i++) + { + ligSetOffsetPositions.Add(writer.BaseStream.Position); + writer.WriteUInt16BigEndian(0); + } + + // --- DATA SERIALIZATION --- + + // 6. Serialize CoverageTable and backfill its offset + if (this.Coverage != null) + { + this.WriteRelativeOffset(writer, subTableStart, covOffsetPos); + this.Coverage.Serialize(writer); + } + + // 7. Serialize LigatureSets (Order must match CoverageTable indices) + ushort[] coveredGlyphs = this.Coverage.GetCoveredGlyphs(); + for (int i = 0; i < coveredGlyphs.Length; i++) + { + ushort baseGlyphId = coveredGlyphs[i]; + + if (this.LigatureSets.TryGetValue(baseGlyphId, out var ligSet)) + { + // Update the offset for this specific set in the array from step 5 + this.WriteRelativeOffset(writer, subTableStart, ligSetOffsetPositions[i]); + + // Serialize the LigatureSetTable (which handles its own internal offsets) + ligSet.Serialize(writer); + } + } + } + + /// + /// Filters the contained LigatureSets based on the subset mapping, + /// removes obsolete ligatures, and reconstructs the CoverageTable. + /// + internal LigatureSubstSubTable CreateSubset(Dictionary oldToNewGlyphId) + { + LigatureSubstSubTable newSubTable = new LigatureSubstSubTable { SubtableFormat = this.SubtableFormat }; + List newBaseGlyphs = new List(); + + // 1. Iterate over existing LigatureSets + foreach (var kvp in this.LigatureSets) + { + ushort oldBaseGlyphId = kvp.Key; + LigatureSetTable oldLigSet = kvp.Value; + + // Check if the starting glyph (e.g., 'f') exists in the subset + if (oldToNewGlyphId.TryGetValue(oldBaseGlyphId, out ushort newBaseGlyphId)) + { + // Create filtered LigatureSet (remapping all internal component GIDs) + LigatureSetTable newLigSet = oldLigSet.CreateSubset(oldToNewGlyphId); + + if (newLigSet != null && newLigSet.Ligatures.Count > 0) + { + // Store using the NEW Glyph ID as the key + newSubTable.LigatureSets[newBaseGlyphId] = newLigSet; + newBaseGlyphs.Add(newBaseGlyphId); + } + } + } + + // 2. Reconstruct the Coverage Table + if (newSubTable.LigatureSets.Count > 0) + { + // OpenType requires the Coverage table glyphs to be sorted numerically + newBaseGlyphs.Sort(); + + newSubTable.Coverage = new CoverageTableFormat1 + { + GlyphCount = (ushort)newBaseGlyphs.Count, + GlyphArray = newBaseGlyphs.ToArray() + }; + } + + return newSubTable.LigatureSets.Count > 0 ? newSubTable : null; + } + + /// + /// Rewrites the subtable using the provided subsetting context. + /// + public LigatureSubstSubTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + var newSubTable = new LigatureSubstSubTable(); + newSubTable.SubtableFormat = this.SubtableFormat; + newSubTable.LigatureSets = new Dictionary(); + + foreach (var oldSet in this.LigatureSets) + { + // 1. Map the start glyph (e.g., 'f') + if (!context.OldToNewGlyphId.TryGetValue(oldSet.Key, out ushort newFirstGid)) + continue; + + var newSet = new LigatureSetTable(); + newSet.Ligatures = new List(); + + foreach (var oldLig in oldSet.Value.Ligatures) + { + // 2. Map the target ligature glyph (e.g., 'fi') + if (!context.OldToNewGlyphId.TryGetValue(oldLig.LigatureGlyph, out ushort newTargetGid)) + continue; + + // 3. Map all components (e.g., 'i' in "fi") + var newComponents = new List(); + bool allComponentsMapped = true; + + foreach (var oldCompGid in oldLig.Components) + { + if (context.OldToNewGlyphId.TryGetValue(oldCompGid, out ushort newCompGid)) + { + newComponents.Add(newCompGid); + } + else + { + allComponentsMapped = false; + break; + } + } + + if (allComponentsMapped) + { + newSet.Ligatures.Add(new LigatureTable + { + LigatureGlyph = newTargetGid, + Components = newComponents.ToArray() + }); + } + } + + if (newSet.Ligatures.Count > 0) + { + newSubTable.LigatureSets[newFirstGid] = newSet; + } + } + + if (newSubTable.LigatureSets.Count > 0) + { + var newBaseGlyphs = new List(newSubTable.LigatureSets.Keys); + newBaseGlyphs.Sort(); // OpenType kräver sorterad Coverage + + newSubTable.Coverage = new CoverageTableFormat1 + { + GlyphCount = (ushort)newBaseGlyphs.Count, + GlyphArray = newBaseGlyphs.ToArray() + }; + } + + return newSubTable.LigatureSets.Count > 0 ? newSubTable : null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureTable.cs new file mode 100644 index 0000000000..ccde738f77 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/LigatureTable.cs @@ -0,0 +1,113 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + public class LigatureTable : FontTableElement + { + /// + /// The Glyph ID of the resulting ligature glyph (output). + /// + public ushort LigatureGlyph { get; set; } + + /// + /// The array of component Glyph IDs that follow the initial glyph (input sequence). + /// Note: The initial glyph is implicitly defined by the Coverage table that points to the LigatureSet. + /// + public ushort[] Components { get; set; } + + + /// + /// Remaps the output ligature glyph ID and all component glyph IDs + /// from old IDs to new subset IDs. + /// + /// The mapping dictionary. + /// True if the LigatureGlyph is included in the subset, otherwise false. + internal bool Remap(Dictionary oldToNewGlyphId) + { + ushort newLigatureGid; + + // 1. Remap the resulting Ligature Glyph ID + if (oldToNewGlyphId.TryGetValue(this.LigatureGlyph, out newLigatureGid)) + { + this.LigatureGlyph = newLigatureGid; + + // 2. Remap component glyph IDs (input sequence) + for (int i = 0; i < this.Components.Length; i++) + { + ushort oldComponentGid = this.Components[i]; + ushort newComponentGid; + + if (oldToNewGlyphId.TryGetValue(oldComponentGid, out newComponentGid)) + { + this.Components[i] = newComponentGid; + } + else + { + // If a component is not in the subset, the ligature is invalid + // and should be discarded later. For now, remap to .notdef (New ID 0). + this.Components[i] = 0; + } + } + return true; + } + + // Ligature output glyph is not in the subset, so this substitution must be removed. + return false; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + // 0: USHORT LigatureGlyph + writer.WriteUInt16BigEndian(this.LigatureGlyph); + + // 2: USHORT ComponentCount (must be Components.Length + 1, as the first glyph is implicit) + writer.WriteUInt16BigEndian((ushort)(this.Components.Length + 1)); + + // 4: USHORT[] ComponentGlyphIDs + foreach (ushort componentGid in this.Components) + { + writer.WriteUInt16BigEndian(componentGid); + } + } + + internal LigatureTable CloneAndRewrite(FontSubsettingContext context) + { + ushort newLigatureGid; + if (!context.GlyphIdMap.TryGetValue(this.LigatureGlyph, out newLigatureGid)) + return null; + + ushort[] newComponents = new ushort[this.Components.Length]; + for (int i = 0; i < this.Components.Length; i++) + { + ushort newCompGid; + if (context.GlyphIdMap.TryGetValue(this.Components[i], out newCompGid)) + { + newComponents[i] = newCompGid; + } + else + { + // Of one component is missing the entire ligature is invalid. + return null; + } + } + + LigatureTable newLig = new LigatureTable(); + newLig.LigatureGlyph = newLigatureGid; + newLig.Components = newComponents; + return newLig; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTable.cs new file mode 100644 index 0000000000..c8e16be228 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTable.cs @@ -0,0 +1,107 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a Single Substitution Subtable (Lookup Type 1). + /// This lookup replaces a single glyph with another single glyph. + /// + public abstract class SingleSubstSubTable : FontTableElement + { + /// + /// Gets or sets the format identifier (1 or 2). + /// + public ushort SubtableFormat { get; set; } + + /// + /// Gets or sets the Coverage table which defines the input glyphs to be substituted. + /// + public CoverageTable Coverage { get; set; } + + /// + /// Returns the substituted glyph ID for a given base glyph ID. + /// + /// The original glyph ID. + /// The new glyph ID after substitution. + public abstract ushort GetSubstitution(ushort baseGlyphId); + + /// + /// Creates a subset of the subtable based on the provided mapping. + /// Note: This implementation maps everything to Format 2 to ensure compatibility + /// when indices are no longer contiguous. + /// + internal virtual SingleSubstSubTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + // Listan för att hålla (Nytt Input GID, Nytt Output GID) + List validMappings = new List(); + + // Hämta alla Glyph IDs som denna tabell hanterar från original-fonten + ushort[] oldInputGlyphs = this.Coverage.GetCoveredGlyphs(); + + foreach (ushort oldInputGid in oldInputGlyphs) + { + // 1. Finns tecknet som triggar bytet (t.ex. 'f') i vårt subset? + if (context.OldToNewGlyphId.TryGetValue(oldInputGid, out ushort newInputGid)) + { + // Hämta vad tecknet skulle bytas ut mot (t.ex. GID 447) + ushort oldOutputGid = GetSubstitution(oldInputGid); + + // 2. Finns ersättningstecknet (GID 447) också i vårt subset? + // DETTA ÄR KRITISKT: Om 447 inte finns i IncludedGlyphs blir det ingen mappning. + if (context.OldToNewGlyphId.TryGetValue(oldOutputGid, out ushort newOutputGid)) + { + validMappings.Add(new GsubRewriteEntry + { + NewInput = newInputGid, + NewOutput = newOutputGid + }); + } + } + } + + if (validMappings.Count == 0) return null; + + // Sortera efter NewInput - ett strikt krav för CoverageTable i OpenType + validMappings.Sort((a, b) => a.NewInput.CompareTo(b.NewInput)); + + // Skapa den nya tabellen som Format 2 (det säkraste för subsetting) + var newTable = new SingleSubstSubTableFormat2(); + List newInputs = new List(); + newTable.SubstituteGlyphIDs = new ushort[validMappings.Count]; + + for (int i = 0; i < validMappings.Count; i++) + { + newInputs.Add(validMappings[i].NewInput); + newTable.SubstituteGlyphIDs[i] = validMappings[i].NewOutput; + } + + // Bygg om Coverage med de NYA GID-numren + newTable.Coverage = CoverageTableFormat2.CreateCoverageFormat2(newInputs); + newTable.GlyphCount = (ushort)validMappings.Count; + newTable.SubtableFormat = 2; + + return newTable; + } + + private struct GsubRewriteEntry + { + public ushort NewInput; + public ushort NewOutput; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat1.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat1.cs new file mode 100644 index 0000000000..45358ca499 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat1.cs @@ -0,0 +1,67 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a Single Substitution Subtable Format 1. + /// This format applies a single constant delta value to a range of glyph IDs. + /// + public class SingleSubstSubTableFormat1 : SingleSubstSubTable + { + /// + /// Gets or sets the delta value added to the original glyph ID to get the substituted glyph ID. + /// + public short DeltaGlyphID { get; set; } + + /// + /// Calculates the substituted glyph ID by adding the delta to the input glyph ID. + /// + /// The original glyph ID. + /// The substituted glyph ID if covered; otherwise, 0. + public override ushort GetSubstitution(ushort baseGlyphId) + { + int index = Coverage.GetGlyphIndex(baseGlyphId); + if (index == -1) return 0; // Glyph is not covered by this subtable + + // Format 1 adds a constant delta to the original GID. + // Wrap-around (modulo 65536) is handled by the ushort cast. + return (ushort)(baseGlyphId + DeltaGlyphID); + } + + internal override void Serialize(FontsBinaryWriter writer) + { + // Store the start position of this subtable for relative offset calculation + long subTableStart = writer.BaseStream.Position; + + // 1. Write SubtableFormat (1) + writer.WriteUInt16BigEndian(1); + + // 2. Placeholder for CoverageOffset (2 bytes) + long covOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); + + // 3. Write DeltaGlyphID (SSHORT) + writer.WriteInt16BigEndian(this.DeltaGlyphID); + + // --- Write CoverageTable --- + if (this.Coverage != null) + { + // Calculate and backfill the relative offset to the Coverage table + this.WriteRelativeOffset(writer, subTableStart, covOffsetPos); + + // Serialize the CoverageTable + this.Coverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat2.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat2.cs new file mode 100644 index 0000000000..66f3872865 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SingleSubstSubTableFormat2.cs @@ -0,0 +1,82 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a Single Substitution Subtable Format 2. + /// This format maps each glyph identified in the Coverage table to a specific + /// substitute glyph ID in a corresponding array. + /// + public class SingleSubstSubTableFormat2 : SingleSubstSubTable + { + /// + /// Gets or sets the number of glyph IDs in the SubstituteGlyphIDs array. + /// + public ushort GlyphCount { get; set; } + + /// + /// Gets or sets the array of substitute glyph IDs, ordered by their corresponding + /// index in the Coverage table. + /// + public ushort[] SubstituteGlyphIDs { get; set; } + + /// + /// Returns the substituted glyph ID by looking up the coverage index in the SubstituteGlyphIDs array. + /// + /// The original glyph ID. + /// The substituted glyph ID if covered; otherwise, 0. + public override ushort GetSubstitution(ushort baseGlyphId) + { + int index = Coverage.GetGlyphIndex(baseGlyphId); + + // Validate that the glyph is covered and the index is within the bounds of our array + if (index == -1 || index >= SubstituteGlyphIDs.Length) + return 0; + + // Format 2 maps the coverage index directly to the substitute array + return SubstituteGlyphIDs[index]; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + // Store start position for relative offset calculation + long startPos = writer.BaseStream.Position; + + // 1. Write SubtableFormat (2) + writer.WriteUInt16BigEndian(2); + + // 2. Placeholder for CoverageOffset (2 bytes) + long covOffsetPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); + + // 3. Write GlyphCount and the array of SubstituteGlyphIDs + ushort count = this.SubstituteGlyphIDs != null ? (ushort)this.SubstituteGlyphIDs.Length : (ushort)0; + writer.WriteUInt16BigEndian(count); + + if (this.SubstituteGlyphIDs != null) + { + foreach (var gid in this.SubstituteGlyphIDs) + { + writer.WriteUInt16BigEndian(gid); + } + } + + // 4. Serialize CoverageTable and backfill the offset + if (this.Coverage != null) + { + this.WriteRelativeOffset(writer, startPos, covOffsetPos); + this.Coverage.Serialize(writer); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SubstLookupRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SubstLookupRecord.cs new file mode 100644 index 0000000000..8f26bd3cdb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/SubstLookupRecord.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups +{ + /// + /// Represents a substitution lookup record within a contextual substitution table. + /// It defines which lookup should be applied to a specific position in the input sequence. + /// + public class SubstLookupRecord + { + /// + /// Gets or sets the zero-based index into the input glyph sequence where the substitution should be applied. + /// + public ushort SequenceIndex { get; set; } + + /// + /// Gets or sets the index of the lookup in the GSUB LookupList that will be triggered for the specified sequence index. + /// + public ushort LookupListIndex { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ValueRecordSerializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ValueRecordSerializer.cs new file mode 100644 index 0000000000..6fd8699397 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Data/Lookups/ValueRecordSerializer.cs @@ -0,0 +1,55 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB ValueRecord serialization + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups +{ + /// + /// Static helper for serializing ValueRecord structures. + /// Used by SinglePos, PairPos, and other positioning lookups. + /// + internal static class ValueRecordSerializer + { + /// + /// Serializes a ValueRecord based on the ValueFormat flags. + /// ValueFormat is a bit field indicating which fields are present. + /// + /// Binary writer + /// ValueRecord to serialize + /// Bit flags indicating which fields to write + public static void Serialize(FontsBinaryWriter writer, ValueRecord record, ushort valueFormat) + { + if (record == null) + return; + + // Bit 0x0001: XPlacement + if ((valueFormat & 0x0001) != 0) + writer.WriteInt16BigEndian(record.XPlacement); + + // Bit 0x0002: YPlacement + if ((valueFormat & 0x0002) != 0) + writer.WriteInt16BigEndian(record.YPlacement); + + // Bit 0x0004: XAdvance + if ((valueFormat & 0x0004) != 0) + writer.WriteInt16BigEndian(record.XAdvance); + + // Bit 0x0008: YAdvance + if ((valueFormat & 0x0008) != 0) + writer.WriteInt16BigEndian(record.YAdvance); + + // Bits 0x0010-0x0080: Device tables (not implemented yet) + // XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice + // We skip these for now + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTable.cs new file mode 100644 index 0000000000..9d2d655654 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTable.cs @@ -0,0 +1,147 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Features; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using EPPlus.Fonts.OpenType.Utils; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub +{ + public class GsubTable : FontTableBase + { + public override string Name => TableNames.Gsub; + public override bool IsEssentialTable => false; + + /// + /// Major version of the GSUB table. Set to 1 for current specification. + /// + public ushort MajorVersion { get; set; } = 1; + + /// + /// Minor version of the GSUB table. 0 for GSUB 1.0, 1 for GSUB 1.1 (required for Variation Support). + /// + public ushort MinorVersion { get; set; } = 0; // Default to 1.0 + + /// + /// ScriptList table. Used for determining which language-specific features apply. + /// + public ScriptListTable ScriptList { get; set; } + + /// + /// FeatureList table. Defines the specific typographic features (e.g., 'liga' for ligatures) + /// that are available in the font and links them to the Lookups that implement them. + /// This list is referenced by ScriptList/LangSys to activate features for a given language. + /// + public FeatureListTable FeatureList { get; set; } + + public LookupListTable LookupList { get; set; } + + internal override void Clear() + { + throw new NotImplementedException(); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + long tableStartOffset = writer.BaseStream.Position; + + // --- HEADER --- + writer.WriteUInt16BigEndian(this.MajorVersion); + writer.WriteUInt16BigEndian(this.MinorVersion); + + long scriptListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + long featureListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + long lookupListOffPos = writer.BaseStream.Position; + writer.WriteUInt16BigEndian(0); // Placeholder + + // GSUB 1.1 FeatureVariations + if (this.MajorVersion == 1 && this.MinorVersion == 1) + writer.WriteUInt32BigEndian(0); + + // --- DATA --- + + // 1. ScriptList + if (this.ScriptList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, scriptListOffPos, this.ScriptList); + } + + // 2. FeatureList + if (this.FeatureList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, featureListOffPos, this.FeatureList); + } + + // 3. LookupList + if (this.LookupList != null) + { + LayoutTableSerializationHelper.UpdateOffsetAndSerialize(writer, tableStartOffset, lookupListOffPos, this.LookupList); + } + } + + /// + /// Rewrites the GSUB table for font subsetting. + /// + /// The subsetting context containing glyph mappings. + /// A new GsubTable containing only the relevant substitutions. + public GsubTable Rewrite(FontSubsettingContext context) + { + var newGsub = new GsubTable(); + newGsub.MajorVersion = this.MajorVersion; + newGsub.MinorVersion = this.MinorVersion; + + // 1. Rewrite Lookups first - creates lookup index mapping + LookupRewriteResult lookupResult = null; + if (this.LookupList != null) + { + lookupResult = this.LookupList.Rewrite(context); + if (lookupResult == null || lookupResult.NewLookupList == null || lookupResult.NewLookupList.Lookups.Count == 0) + { + // No lookups remain - return null or minimal table + return null; + } + newGsub.LookupList = lookupResult.NewLookupList; + } + + // 2. Rewrite FeatureList - pass lookup index mapping, get feature index mapping back + FeatureRewriteResult featureResult = null; + if (this.FeatureList != null && lookupResult != null) + { + featureResult = this.FeatureList.Rewrite(context, lookupResult.OldToNewIndexMap); + if (featureResult == null || featureResult.NewFeatureList == null || featureResult.NewFeatureList.FeatureRecords.Count == 0) + { + // No features remain + return null; + } + newGsub.FeatureList = featureResult.NewFeatureList; + } + + // 3. Rewrite ScriptList - pass feature index mapping + if (this.ScriptList != null && featureResult != null) + { + newGsub.ScriptList = this.ScriptList.Rewrite(context, featureResult.OldToNewIndexMap); + } + + return newGsub; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableLoader.cs new file mode 100644 index 0000000000..ec1137cf2f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableLoader.cs @@ -0,0 +1,164 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/07/2026 EPPlus Software AB Refactored to use shared loaders + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Features; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using EPPlus.Fonts.OpenType.Tables.Gsub.IO; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub +{ + /// + /// Loads the GSUB (Glyph Substitution) table from an OpenType font. + /// Manages the hierarchical loading of Scripts, Features, and Lookups. + /// + internal class GsubTableLoader : TableLoader + { + public GsubTableLoader(TableLoaderSettings tblSettings) : base(tblSettings, TableNames.Gsub) + { + _settings = tblSettings; + } + + private readonly TableLoaderSettings _settings; + + protected override GsubTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + long tableStartOffset = _offset; + + // Read GSUB Header + ushort major = _reader.ReadUInt16BigEndian(); + ushort minor = _reader.ReadUInt16BigEndian(); + + if (major != 1) + { + // Unsupported version + return null; + } + + var gsubTable = new GsubTable + { + MajorVersion = major, + MinorVersion = minor, + }; + + // Read Offsets + ushort scriptListOffset = _reader.ReadUInt16BigEndian(); + ushort featureListOffset = _reader.ReadUInt16BigEndian(); + ushort lookupListOffset = _reader.ReadUInt16BigEndian(); + + // ✅ Use shared loaders from Common.Layout + if (scriptListOffset > 0) + { + _reader.BaseStream.Seek(tableStartOffset + scriptListOffset, SeekOrigin.Begin); + gsubTable.ScriptList = ScriptListTableLoader.Load(_reader, tableStartOffset + scriptListOffset); + } + + if (featureListOffset > 0) + { + _reader.BaseStream.Seek(tableStartOffset + featureListOffset, SeekOrigin.Begin); + gsubTable.FeatureList = FeatureListTableLoader.Load(_reader, tableStartOffset + featureListOffset); + } + + if (lookupListOffset > 0) + { + _reader.BaseStream.Seek(tableStartOffset + lookupListOffset, SeekOrigin.Begin); + gsubTable.LookupList = LoadLookupList(tableStartOffset + lookupListOffset); + } + + return gsubTable; + } + + #region LookupList loading (GSUB-specific) + + private LookupListTable LoadLookupList(long lookupListStartOffset) + { + LookupListTable lookupList = new LookupListTable(); + ushort lookupCount = _reader.ReadUInt16BigEndian(); + + ushort[] lookupOffsets = new ushort[lookupCount]; + for (int i = 0; i < lookupCount; i++) + { + lookupOffsets[i] = _reader.ReadUInt16BigEndian(); + } + + long currentPosition = _reader.BaseStream.Position; + + foreach (ushort offset in lookupOffsets) + { + _reader.BaseStream.Seek(lookupListStartOffset + offset, SeekOrigin.Begin); + lookupList.Lookups.Add(LoadLookupTable()); + } + + _reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); + return lookupList; + } + + private LookupTable LoadLookupTable() + { + LookupTable lookupTable = new LookupTable(); + long lookupTableStartOffset = _reader.BaseStream.Position; + + lookupTable.LookupType = _reader.ReadUInt16BigEndian(); + lookupTable.LookupFlag = _reader.ReadUInt16BigEndian(); + lookupTable.SubTableCount = _reader.ReadUInt16BigEndian(); + + ushort[] subTableOffsets = new ushort[lookupTable.SubTableCount]; + for (int i = 0; i < lookupTable.SubTableCount; i++) + { + subTableOffsets[i] = _reader.ReadUInt16BigEndian(); + } + + long positionAfterOffsets = _reader.BaseStream.Position; + + for (int i = 0; i < lookupTable.SubTableCount; i++) + { + long subTableAbsoluteStart = lookupTableStartOffset + subTableOffsets[i]; + FontTableElement subTable = null; + + // GSUB-specific subtable loading + switch (lookupTable.LookupType) + { + case 1: // Single Substitution + subTable = new SingleSubstSubTableDeserializer(_reader).Deserialize(subTableAbsoluteStart); + break; + case 4: // Ligature Substitution + subTable = new LigatureSubstSubTableDeserializer(_reader).Deserialize(subTableAbsoluteStart); + break; + case 6: // Chaining Contextual Substitution + subTable = new ChainingContextualDeserializer(_reader).Deserialize(subTableAbsoluteStart); + break; + case 7: // Extension Substitution + subTable = new ExtensionSubstSubTableDeserializer(_reader).Deserialize(subTableAbsoluteStart); + break; + default: + // Unknown lookup type - skip + break; + } + + if (subTable != null) + { + lookupTable.SubTables.Add(subTable); + } + } + + _reader.BaseStream.Seek(positionAfterOffsets, SeekOrigin.Begin); + return lookupTable; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableValidator.cs new file mode 100644 index 0000000000..8e2295256e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/GsubTableValidator.cs @@ -0,0 +1,726 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/09/2026 EPPlus Software AB Enhanced validation for all GSUB types + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Features; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub +{ + internal class GsubTableValidator : TableValidatorBase + { + public override Type TableType => typeof(GsubTable); + public override string TableName => TableNames.Gsub; + + public override TableValidationResult Validate(GsubTable table, FontValidationContext context) + { + var result = new TableValidationResult { TableName = TableName, LogLevel = base.LogLevel }; + var numGlyphs = context.Font.MaxpTable?.numGlyphs ?? 0; + + if (table == null) return result; + + // 1. Validate version + if (table.MajorVersion != 1) + { + result.AddMessage(FontValidationSeverity.Error, + $"GSUB version {table.MajorVersion}.{table.MinorVersion} is not supported. Expected 1.x"); + return result; // Cannot continue if version is wrong + } + + // 2. Validate ScriptListTable + ValidateScriptList(table.ScriptList, result); + + // 3. Validate FeatureListTable + int totalLookups = table.LookupList?.Lookups.Count ?? 0; + ValidateFeatureList(table.FeatureList, result, totalLookups); + + // 4. Validate LookupListTable + ValidateLookupList(table.LookupList, result, numGlyphs); + + return result; + } + + #region ScriptList Validation + + private void ValidateScriptList(ScriptListTable scriptList, TableValidationResult result) + { + if (scriptList == null || scriptList.ScriptRecords == null) + { + result.AddMessage(FontValidationSeverity.Warning, "GSUB ScriptListTable is missing or null."); + return; + } + + if (scriptList.ScriptRecords.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "GSUB ScriptListTable has no scripts."); + return; + } + + for (int i = 0; i < scriptList.ScriptRecords.Count; i++) + { + var record = scriptList.ScriptRecords[i]; + + // Validate the Tag + if (record.ScriptTag == null || string.IsNullOrEmpty(record.ScriptTag.Value)) + { + result.AddMessage(FontValidationSeverity.Error, + $"ScriptRecord at index {i} has a null or empty ScriptTag."); + } + else if (record.ScriptTag.Value.Length != 4) + { + result.AddMessage(FontValidationSeverity.Error, + $"ScriptRecord index {i} has invalid tag length: '{record.ScriptTag.Value}' (must be 4 characters)."); + } + + // Check alphabetical sorting of tags (required by OpenType spec) + if (i > 0 && record.ScriptTag != null && scriptList.ScriptRecords[i - 1].ScriptTag != null) + { + if (string.CompareOrdinal(scriptList.ScriptRecords[i - 1].ScriptTag.Value, record.ScriptTag.Value) >= 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"ScriptRecords are not sorted alphabetically: '{scriptList.ScriptRecords[i - 1].ScriptTag.Value}' before '{record.ScriptTag.Value}'."); + } + } + + // Validate the associated ScriptTable + if (record.ScriptTable == null) + { + result.AddMessage(FontValidationSeverity.Error, + $"ScriptRecord '{record.ScriptTag?.Value}' is missing its ScriptTable."); + continue; + } + + ValidateScriptTable(record.ScriptTable, record.ScriptTag?.Value, result); + } + } + + private void ValidateScriptTable(ScriptTable scriptTable, string scriptTag, TableValidationResult result) + { + if (scriptTable.DefaultLangSys == null && + (scriptTable.LangSysRecords == null || scriptTable.LangSysRecords.Count == 0)) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Script '{scriptTag}' has no language systems (no DefaultLangSys and no LangSysRecords)."); + return; + } + + // Validate DefaultLangSys + if (scriptTable.DefaultLangSys != null) + { + ValidateLangSys(scriptTable.DefaultLangSys, $"{scriptTag} (default)", result); + } + + // Validate LangSysRecords + if (scriptTable.LangSysRecords != null) + { + for (int i = 0; i < scriptTable.LangSysRecords.Count; i++) + { + var langRecord = scriptTable.LangSysRecords[i]; + + if (langRecord.LangSysTable != null) + { + ValidateLangSys(langRecord.LangSysTable, + $"{scriptTag}/{langRecord.LangSysTag:X8}", result); + } + + // Check for sorted language tags + if (i > 0) + { + uint prevTag = scriptTable.LangSysRecords[i - 1].LangSysTag; + uint currTag = langRecord.LangSysTag; + if (prevTag >= currTag) + { + result.AddMessage(FontValidationSeverity.Error, + $"Script '{scriptTag}': LangSysRecords not sorted (0x{prevTag:X8} >= 0x{currTag:X8})."); + } + } + } + } + } + + private void ValidateLangSys(LangSysTable langSys, string context, TableValidationResult result) + { + // LookupOrder must be 0 (reserved) + if (langSys.LookupOrder != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"{context}: LookupOrder is {langSys.LookupOrder} (should be 0 - reserved field)."); + } + + // Validate FeatureIndices + if (langSys.FeatureIndices != null) + { + for (int i = 0; i < langSys.FeatureIndices.Length; i++) + { + // Check for sorted indices (should be ascending) + if (i > 0 && langSys.FeatureIndices[i] <= langSys.FeatureIndices[i - 1]) + { + result.AddMessage(FontValidationSeverity.Warning, + $"{context}: FeatureIndices not sorted at index {i}."); + } + } + } + } + + #endregion + + #region FeatureList Validation + + private void ValidateFeatureList(FeatureListTable featureList, TableValidationResult result, int totalLookups) + { + if (featureList == null || featureList.FeatureRecords == null) + { + result.AddMessage(FontValidationSeverity.Warning, "GSUB FeatureListTable is missing or null."); + return; + } + + for (int i = 0; i < featureList.FeatureRecords.Count; i++) + { + var record = featureList.FeatureRecords[i]; + + // Validate Tag + if (record.FeatureTag == null || string.IsNullOrEmpty(record.FeatureTag.Value)) + { + result.AddMessage(FontValidationSeverity.Error, + $"FeatureRecord at index {i} has null or empty tag."); + continue; + } + + if (record.FeatureTag.Value.Length != 4) + { + result.AddMessage(FontValidationSeverity.Error, + $"FeatureRecord at index {i} has invalid tag length: '{record.FeatureTag.Value}'."); + } + + // Validate Tag sorting (features should be sorted alphabetically) + if (i > 0 && featureList.FeatureRecords[i - 1].FeatureTag != null) + { + if (string.CompareOrdinal(featureList.FeatureRecords[i - 1].FeatureTag.Value, + record.FeatureTag.Value) > 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"FeatureRecords are not sorted alphabetically: '{featureList.FeatureRecords[i - 1].FeatureTag.Value}' before '{record.FeatureTag.Value}'."); + } + } + + // Validate FeatureTable + if (record.FeatureTable == null) + { + result.AddMessage(FontValidationSeverity.Error, + $"Feature '{record.FeatureTag.Value}' has null FeatureTable."); + continue; + } + + ValidateFeatureTable(record.FeatureTable, record.FeatureTag.Value, result, totalLookups); + } + } + + private void ValidateFeatureTable(FeatureTable featureTable, string featureTag, + TableValidationResult result, int totalLookups) + { + if (featureTable.LookupListIndices == null || featureTable.LookupListIndices.Length == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Feature '{featureTag}' has no lookup indices (will have no effect)."); + return; + } + + foreach (var lookupIdx in featureTable.LookupListIndices) + { + if (lookupIdx >= totalLookups) + { + result.AddMessage(FontValidationSeverity.Error, + $"Feature '{featureTag}' references out-of-bounds LookupIndex {lookupIdx} (max: {totalLookups - 1})."); + } + } + } + + #endregion + + #region LookupList Validation + + private void ValidateLookupList(LookupListTable lookupList, TableValidationResult result, int numGlyphs) + { + if (lookupList == null || lookupList.Lookups == null) + { + result.AddMessage(FontValidationSeverity.Warning, "GSUB LookupListTable is missing or null."); + return; + } + + for (int i = 0; i < lookupList.Lookups.Count; i++) + { + var lookup = lookupList.Lookups[i]; + + // Validate LookupType + if (lookup.LookupType < 1 || lookup.LookupType > 8) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {i}: Invalid LookupType {lookup.LookupType} (must be 1-8)."); + continue; + } + + // Validate LookupFlags + ValidateLookupFlags(lookup, i, result); + + // Validate SubTables + if (lookup.SubTables == null || lookup.SubTables.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {i} (Type: {lookup.LookupType}) has no subtables (will have no effect)."); + continue; + } + + foreach (var subtable in lookup.SubTables) + { + ValidateSubtable(subtable, lookup.LookupType, i, result, numGlyphs); + } + } + } + + private void ValidateLookupFlags(LookupTable lookup, int lookupIdx, TableValidationResult result) + { + // Check reserved bits (bits 8-15 should be 0) + if ((lookup.LookupFlag & 0xFF00) != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx}: Reserved high bits in LookupFlag are set (0x{lookup.LookupFlag:X4})."); + } + + // If UseMarkFilteringSet flag (0x0010) is set, MarkFilteringSet should exist + if ((lookup.LookupFlag & 0x0010) != 0) + { + if (lookup.MarkFilteringSet == null) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: UseMarkFilteringSet flag is set but MarkFilteringSet is null."); + } + } + } + + #endregion + + #region Subtable Validation + + private void ValidateSubtable(FontTableElement subtable, ushort lookupType, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + if (subtable == null) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Subtable is null."); + return; + } + + if (subtable is SingleSubstSubTable single) + { + ValidateSingleSubst(single, lookupIdx, result, numGlyphs); + } + else if (subtable is LigatureSubstSubTable lig) + { + ValidateLigatureSubst(lig, lookupIdx, result, numGlyphs); + } + else if (subtable is ChainingContextualSubstFormat3 chain) + { + ValidateChainingContextualFormat3(chain, lookupIdx, result, numGlyphs); + } + else if (subtable is ExtensionSubstSubTable ext) + { + ValidateExtensionSubst(ext, lookupIdx, result, numGlyphs); + } + else + { + // Unknown or unimplemented subtable type + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx} (Type {lookupType}): Subtable type {subtable.GetType().Name} validation not implemented."); + } + } + + private void ValidateChainingContextualFormat3(ChainingContextualSubstFormat3 chain, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + // Validate Input coverages (required) + if (chain.InputCoverages == null || chain.InputCoverages.Count == 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: ChainContext Format3 has no Input coverages (required)."); + return; + } + + // Validate all coverage tables + int covIdx = 0; + if (chain.BacktrackCoverages != null) + { + foreach (var cov in chain.BacktrackCoverages) + { + ValidateCoverage(cov, $"Lookup {lookupIdx} ChainContext Backtrack[{covIdx++}]", result, numGlyphs); + } + } + + covIdx = 0; + foreach (var cov in chain.InputCoverages) + { + ValidateCoverage(cov, $"Lookup {lookupIdx} ChainContext Input[{covIdx++}]", result, numGlyphs); + } + + covIdx = 0; + if (chain.LookaheadCoverages != null) + { + foreach (var cov in chain.LookaheadCoverages) + { + ValidateCoverage(cov, $"Lookup {lookupIdx} ChainContext Lookahead[{covIdx++}]", result, numGlyphs); + } + } + + // Validate SubstLookupRecords + if (chain.SubstLookupRecords != null) + { + foreach (var record in chain.SubstLookupRecords) + { + if (record.SequenceIndex >= chain.InputCoverages.Count) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: SubstLookupRecord SequenceIndex {record.SequenceIndex} exceeds Input count {chain.InputCoverages.Count}."); + } + } + } + } + + #endregion + + #region Single Substitution Validation + + private void ValidateSingleSubst(SingleSubstSubTable single, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + ValidateCoverage(single.Coverage, $"Lookup {lookupIdx} (SingleSubst)", result, numGlyphs); + + if (single is SingleSubstSubTableFormat1 f1) + { + ValidateSingleSubstFormat1(f1, lookupIdx, result, numGlyphs); + } + else if (single is SingleSubstSubTableFormat2 f2) + { + ValidateSingleSubstFormat2(f2, single.Coverage, lookupIdx, result, numGlyphs); + } + else + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Unknown SingleSubst format."); + } + } + + private void ValidateSingleSubstFormat1(SingleSubstSubTableFormat1 f1, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + // Validate that delta doesn't produce out-of-range glyphs + var coveredGlyphs = f1.Coverage?.GetCoveredGlyphs() ?? new ushort[0]; + + foreach (var gid in coveredGlyphs) + { + // DeltaGlyphID is signed, so cast for proper arithmetic + int resultGid = gid + (short)f1.DeltaGlyphID; + + if (resultGid < 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx} Format1: Delta {(short)f1.DeltaGlyphID} produces negative glyph ID for glyph {gid} → {resultGid}."); + } + else if (resultGid >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx} Format1: Delta {(short)f1.DeltaGlyphID} produces out-of-range glyph ID for glyph {gid} → {resultGid} (max: {numGlyphs - 1})."); + } + } + } + + private void ValidateSingleSubstFormat2(SingleSubstSubTableFormat2 f2, CoverageTable coverage, + int lookupIdx, TableValidationResult result, int numGlyphs) + { + if (f2.SubstituteGlyphIDs == null || f2.SubstituteGlyphIDs.Length == 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx} Format2: SubstituteGlyphIDs is null or empty."); + return; + } + + // Validate each substitute glyph ID + foreach (var gid in f2.SubstituteGlyphIDs) + { + if (gid >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx} Format2: Substitute glyph ID {gid} is out of range (max: {numGlyphs - 1})."); + } + } + + // Validate count matches coverage + int coverageCount = GetCoverageGlyphCount(coverage); + if (f2.SubstituteGlyphIDs.Length != coverageCount) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx} Format2: SubstituteGlyphIDs count ({f2.SubstituteGlyphIDs.Length}) does not match Coverage count ({coverageCount})."); + } + } + + #endregion + + #region Ligature Substitution Validation + + private void ValidateLigatureSubst(LigatureSubstSubTable lig, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + ValidateCoverage(lig.Coverage, $"Lookup {lookupIdx} (LigatureSubst)", result, numGlyphs); + + if (lig.LigatureSets == null || lig.LigatureSets.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx}: LigatureSubst has no ligature sets."); + return; + } + + foreach (var kvp in lig.LigatureSets) + { + ushort firstGlyph = kvp.Key; + var ligSet = kvp.Value; + + if (ligSet == null || ligSet.Ligatures == null || ligSet.Ligatures.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx}: LigatureSet for glyph {firstGlyph} is empty."); + continue; + } + + foreach (var ligature in ligSet.Ligatures) + { + ValidateLigatureTable(ligature, firstGlyph, lookupIdx, result, numGlyphs); + } + } + } + + private void ValidateLigatureTable(LigatureTable ligature, ushort firstGlyph, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + // Validate output glyph + if (ligature.LigatureGlyph >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Ligature output glyph {ligature.LigatureGlyph} is out of range (max: {numGlyphs - 1})."); + } + + // Validate component count + if (ligature.Components == null || ligature.Components.Length == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx}: Ligature {firstGlyph} → {ligature.LigatureGlyph} has no components (should have at least 1)."); + return; + } + + // Validate each component + foreach (var compGid in ligature.Components) + { + if (compGid >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Ligature component glyph {compGid} is out of range (max: {numGlyphs - 1})."); + } + } + + // Check for potential circular references + if (ligature.LigatureGlyph >= 400) + { + foreach (var compGid in ligature.Components) + { + if (compGid >= 400) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Lookup {lookupIdx}: Ligature {ligature.LigatureGlyph} uses component {compGid} which may be another ligature (potential circular dependency)."); + } + } + } + + // MA 260119: Fails for NotoEmoji, below is not covering a full circular reference and was disabled. + + //// Check for self-reference + //if (firstGlyph == ligature.LigatureGlyph || ligature.Components.Contains(ligature.LigatureGlyph)) + //{ + // result.AddMessage(FontValidationSeverity.Error, + // $"Lookup {lookupIdx}: Ligature {ligature.LigatureGlyph} references itself (circular dependency)."); + //} + } + + #endregion + + #region Extension Substitution Validation + + private void ValidateExtensionSubst(ExtensionSubstSubTable ext, int lookupIdx, + TableValidationResult result, int numGlyphs) + { + // Extension cannot wrap another extension + if (ext.ExtensionLookupType == 7) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Extension substitution cannot reference another extension (Type 7)."); + return; + } + + // Validate extension lookup type range + if (ext.ExtensionLookupType < 1 || ext.ExtensionLookupType > 8) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Invalid ExtensionLookupType {ext.ExtensionLookupType} (must be 1-8, not 7)."); + return; + } + + // Validate wrapped subtable exists + if (ext.ExtendedSubTable == null) + { + result.AddMessage(FontValidationSeverity.Error, + $"Lookup {lookupIdx}: Extension has no wrapped subtable."); + return; + } + + // Recursively validate the wrapped subtable + ValidateSubtable(ext.ExtendedSubTable, ext.ExtensionLookupType, lookupIdx, result, numGlyphs); + } + + #endregion + + #region Coverage Validation + + private void ValidateCoverage(CoverageTable coverage, string context, + TableValidationResult result, int numGlyphs) + { + if (coverage == null) + { + result.AddMessage(FontValidationSeverity.Error, $"{context}: CoverageTable is missing."); + return; + } + + if (coverage is CoverageTableFormat1 f1) + { + ValidateCoverageFormat1(f1, context, result, numGlyphs); + } + else if (coverage is CoverageTableFormat2 f2) + { + ValidateCoverageFormat2(f2, context, result, numGlyphs); + } + else + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: Unknown CoverageTable format."); + } + } + + private void ValidateCoverageFormat1(CoverageTableFormat1 f1, string context, + TableValidationResult result, int numGlyphs) + { + if (f1.GlyphArray == null || f1.GlyphArray.Length == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"{context}: Coverage Format1 has empty GlyphArray."); + return; + } + + for (int i = 0; i < f1.GlyphArray.Length; i++) + { + var gid = f1.GlyphArray[i]; + + // Check range + if (gid >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: Coverage glyph ID {gid} at index {i} is out of range (max: {numGlyphs - 1})."); + } + + // Check strict ascending order (required by spec) + if (i > 0 && gid <= f1.GlyphArray[i - 1]) + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: Coverage GlyphArray not strictly ascending at index {i} ({f1.GlyphArray[i - 1]} → {gid})."); + } + } + } + + private void ValidateCoverageFormat2(CoverageTableFormat2 f2, string context, + TableValidationResult result, int numGlyphs) + { + if (f2.RangeRecords == null || f2.RangeRecords.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"{context}: Coverage Format2 has no RangeRecords."); + return; + } + + for (int i = 0; i < f2.RangeRecords.Count; i++) + { + var range = f2.RangeRecords[i]; + + // Check range validity + if (range.StartGlyphID > range.EndGlyphID) + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: RangeRecord {i} has StartGlyphID ({range.StartGlyphID}) > EndGlyphID ({range.EndGlyphID})."); + } + + // Check glyph IDs are in range + if (range.StartGlyphID >= numGlyphs || range.EndGlyphID >= numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: RangeRecord {i} contains out-of-range glyph IDs ({range.StartGlyphID}-{range.EndGlyphID}, max: {numGlyphs - 1})."); + } + + // Check for overlapping or unsorted ranges + if (i > 0) + { + var prevRange = f2.RangeRecords[i - 1]; + if (range.StartGlyphID <= prevRange.EndGlyphID) + { + result.AddMessage(FontValidationSeverity.Error, + $"{context}: RangeRecords overlap or not sorted at index {i} (prev: {prevRange.StartGlyphID}-{prevRange.EndGlyphID}, curr: {range.StartGlyphID}-{range.EndGlyphID})."); + } + } + } + } + + private int GetCoverageGlyphCount(CoverageTable coverage) + { + if (coverage is CoverageTableFormat1 f1) + { + return f1.GlyphArray?.Length ?? 0; + } + + if (coverage is CoverageTableFormat2 f2) + { + int count = 0; + if (f2.RangeRecords != null) + { + foreach (var r in f2.RangeRecords) + { + count += (r.EndGlyphID - r.StartGlyphID + 1); + } + } + return count; + } + + return 0; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ChainingContextualHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ChainingContextualHandler.cs new file mode 100644 index 0000000000..3a420dd29c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ChainingContextualHandler.cs @@ -0,0 +1,84 @@ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Handlers +{ + internal class ChainingContextualHandler : IGsubLookupHandler + { + public ushort LookupType => 6; + + public void Discover(FontSubsettingContext context, LookupTable lookup, GsubSubsetProcessor processor) + { + foreach (var subTable in lookup.SubTables.OfType()) + { + // 1. Check if we have a match on the first character (e.g., 'f') + // Using the name InputCoverage here as it's most common in format 3 + if (subTable.InputCoverages != null && subTable.InputCoverages.Count > 0) + { + var initialCoverage = subTable.InputCoverages[0]; + + if (AnyGlyphInSubset(initialCoverage, context.IncludedGlyphs)) + { + // 2. Loop through records to find linked lookups + foreach (var record in subTable.SubstLookupRecords) + { + int lookupIndex = record.LookupListIndex; + + // 3. Get the actual LookupTable instance from the original font + // We go through context.OriginalFont to find the correct table in the list + if (lookupIndex >= 0 && lookupIndex < context.OriginalFont.GsubTable.LookupList.Lookups.Count) + { + var targetLookup = context.OriginalFont.GsubTable.LookupList.Lookups[lookupIndex]; + + // 4. Now the argument matches! (context, LookupTable) + processor.DiscoverLookup(context, targetLookup); + } + } + } + } + } + } + + private bool AnyGlyphInSubset(CoverageTable coverage, HashSet includedGlyphs) + { + if (coverage == null) return false; + // Get all GIDs that this coverage table includes + var coveredGids = coverage.GetCoveredGlyphs(); + // Check if any of these GIDs exist in our current subset + return coveredGids.Any(gid => includedGlyphs.Contains(gid)); + } + + public LookupTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + var newLookup = new LookupTable + { + LookupType = 6, + LookupFlag = oldLookup.LookupFlag, + SubTables = new List() + }; + + foreach (var subtable in oldLookup.SubTables.OfType()) + { + var rewritten = subtable.Rewrite(context); + + if (rewritten != null) + { + newLookup.SubTables.Add(rewritten); + } + } + + if (newLookup.SubTables.Count > 0) + { + return newLookup; + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ExtensionSubstHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ExtensionSubstHandler.cs new file mode 100644 index 0000000000..65eeb092d8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/ExtensionSubstHandler.cs @@ -0,0 +1,60 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Handlers +{ + internal class ExtensionSubstHandler : IGsubLookupHandler + { + public ushort LookupType => 7; + + public void Discover(FontSubsettingContext context, LookupTable lookup, GsubSubsetProcessor processor) + { + foreach (var subTable in lookup.SubTables.OfType()) + { + // Extension-tabellen är bara en skal som pekar på den riktiga datan + if (subTable.ExtendedSubTable == null) continue; + + // Vi skapar en "fejkad" LookupTable som vi kan skicka vidare till processorn + // för att återanvända den logik vi redan har för t.ex. Typ 4. + var dummyLookup = new LookupTable + { + LookupType = subTable.ExtensionLookupType, + LookupFlag = lookup.LookupFlag, + SubTables = new List { subTable.ExtendedSubTable } + }; + + // Nu skickar vi tillbaka den inre tabellen till processorn + processor.DiscoverLookup(context, dummyLookup); + } + } + + public LookupTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + // För Rewrite låter vi din befintliga arkitektur sköta omskrivningen av subtabeller + var newLookup = new LookupTable { LookupType = 7, LookupFlag = oldLookup.LookupFlag, SubTables = new List() }; + foreach (var subtable in oldLookup.SubTables.OfType()) + { + var rewritten = subtable.Rewrite(context, oldLookup); + if (rewritten != null) newLookup.SubTables.Add(rewritten); + } + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/IGsubLookupHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/IGsubLookupHandler.cs new file mode 100644 index 0000000000..235875354e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/IGsubLookupHandler.cs @@ -0,0 +1,28 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Handlers +{ + internal interface IGsubLookupHandler + { + ushort LookupType { get; } + + // Phase 1: Identify which glyphs are affected and should be included in the subset + void Discover(FontSubsettingContext context, LookupTable lookup, GsubSubsetProcessor processor); + + // Phase 2: Create a new, filtered table based on the included glyphs + LookupTable Rewrite(FontSubsettingContext context, LookupTable oldLookup); + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/LigatureSubstHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/LigatureSubstHandler.cs new file mode 100644 index 0000000000..54ffdc3f44 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/LigatureSubstHandler.cs @@ -0,0 +1,137 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Handlers +{ + internal class LigatureSubstHandler : IGsubLookupHandler + { + public ushort LookupType => 4; + + public void Discover(FontSubsettingContext context, LookupTable lookup, GsubSubsetProcessor processor) + { + bool addedAny; + int iterationCount = 0; + + do + { + iterationCount++; + addedAny = false; + + foreach (var subtable in lookup.SubTables) + { + LigatureSubstSubTable ligSubtable = subtable as LigatureSubstSubTable; + if (ligSubtable == null || ligSubtable.LigatureSets == null) continue; + + foreach (var kvp in ligSubtable.LigatureSets) + { + ushort firstGlyphId = kvp.Key; + + if (!context.IncludedGlyphs.Contains(firstGlyphId)) + continue; + + foreach (var lig in kvp.Value.Ligatures) + { + if (context.IncludedGlyphs.Contains(lig.LigatureGlyph)) + continue; + + // ✅ SIMPLIFIED: Only check base character components (< 400) + bool allBaseComponentsExist = true; + + if (lig.Components != null && lig.Components.Length > 0) + { + foreach (ushort compGid in lig.Components) + { + // ✅ Only validate base characters (< 400) + if (compGid < 400) + { + if (!context.IncludedGlyphs.Contains(compGid)) + { + allBaseComponentsExist = false; + break; + } + } + // Ligature components (>= 400) are completely ignored + } + } + + if (allBaseComponentsExist) + { + context.IncludedGlyphs.Add(lig.LigatureGlyph); + addedAny = true; + } + } + } + } + } while (addedAny); + } + + public LookupTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + + var newLookup = new LookupTable + { + LookupType = 4, + LookupFlag = oldLookup.LookupFlag, + SubTables = new List() + }; + + foreach (var oldSubtable in oldLookup.SubTables) + { + LigatureSubstSubTable oldLigSubtable = oldSubtable as LigatureSubstSubTable; + if (oldLigSubtable == null) continue; + if (oldLigSubtable.LigatureSets == null) continue; + + var newSubTable = new LigatureSubstSubTable(); + newSubTable.SubtableFormat = 1; + newSubTable.LigatureSets = new Dictionary(); + + foreach (var kvp in oldLigSubtable.LigatureSets) + { + ushort oldFirstGid = kvp.Key; + + if (!context.OldToNewGlyphId.TryGetValue(oldFirstGid, out ushort newFirstGid)) + continue; + + var rewrittenSet = kvp.Value.Rewrite(context); + if (rewrittenSet != null && rewrittenSet.Ligatures.Count > 0) + { + newSubTable.LigatureSets[newFirstGid] = rewrittenSet; + } + } + + if (newSubTable.LigatureSets.Count > 0) + { + var coveredGids = new List(newSubTable.LigatureSets.Keys); + coveredGids.Sort(); + + newSubTable.Coverage = new CoverageTableFormat1 + { + CoverageFormat = 1, + GlyphArray = coveredGids.ToArray(), + GlyphCount = (ushort)coveredGids.Count + }; + + newLookup.SubTables.Add(newSubTable); + } + } + + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/SingleSubstHandler.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/SingleSubstHandler.cs new file mode 100644 index 0000000000..3e62d9877b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/Handlers/SingleSubstHandler.cs @@ -0,0 +1,104 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Subsetting; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.Handlers +{ + internal class SingleSubstHandler : IGsubLookupHandler + { + public ushort LookupType => 1; + + public void Discover(FontSubsettingContext context, LookupTable lookup, GsubSubsetProcessor processor) + { + // Loop until no new glyphs are added to capture transitive substitution chains + bool glyphsAdded; + do + { + glyphsAdded = false; + var currentGlyphs = context.IncludedGlyphs.ToArray(); + + foreach (var subtable in lookup.SubTables.OfType()) + { + foreach (ushort gid in currentGlyphs) + { + ushort substitute = subtable.GetSubstitution(gid); + + if (substitute != 0 && !context.IncludedGlyphs.Contains(substitute)) + { + context.IncludedGlyphs.Add(substitute); + glyphsAdded = true; + } + } + } + } while (glyphsAdded); + } + + public LookupTable Rewrite(FontSubsettingContext context, LookupTable oldLookup) + { + var newLookup = new LookupTable { LookupType = 1, LookupFlag = oldLookup.LookupFlag, SubTables = new List() }; + + foreach (var subtable in oldLookup.SubTables.OfType()) + { + var oldMappings = GetMappings(subtable); + var validMappings = new List(); + + // Remap to subset glyph IDs, keeping only mappings where both input and output glyphs are included + foreach (var map in oldMappings) + { + if (context.OldToNewGlyphId.TryGetValue(map.Key, out ushort newInputGid) && + context.OldToNewGlyphId.TryGetValue(map.Value, out ushort newOutputGid)) + { + validMappings.Add(new GsubRewriteEntry { NewInput = newInputGid, NewOutput = newOutputGid }); + } + } + + if (validMappings.Count > 0) + { + validMappings.Sort((a, b) => a.NewInput.CompareTo(b.NewInput)); + var newSub = new SingleSubstSubTableFormat2 + { + SubstituteGlyphIDs = validMappings.Select(m => m.NewOutput).ToArray(), + Coverage = CoverageTableFormat2.CreateCoverageFormat2(validMappings.Select(m => m.NewInput).ToList()), + GlyphCount = (ushort)validMappings.Count, + SubtableFormat = 2 + }; + newLookup.SubTables.Add(newSub); + } + } + return newLookup.SubTables.Count > 0 ? newLookup : null; + } + + private Dictionary GetMappings(SingleSubstSubTable subtable) + { + var mappings = new Dictionary(); + var inputGids = subtable.Coverage.GetCoveredGlyphs(); + + foreach (var oldGid in inputGids) + { + ushort substitutedGid = subtable.GetSubstitution(oldGid); + + if (substitutedGid != 0) + { + mappings[oldGid] = substitutedGid; + } + } + + return mappings; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ChainingContextualDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ChainingContextualDeserializer.cs new file mode 100644 index 0000000000..38936ed8ad --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ChainingContextualDeserializer.cs @@ -0,0 +1,118 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.Collections.Generic; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + /// + /// Deserializes Chaining Contextual Substitution subtables from the GSUB table. + /// Currently supports Format 3 (Coverage-based context) only. + /// Format 1 (Simple context) and Format 2 (Class-based context) are not implemented. + /// Format 3 is the most common format in modern fonts and sufficient for most use cases. + /// + internal class ChainingContextualDeserializer + { + private readonly FontsBinaryReader _reader; + + public ChainingContextualDeserializer(FontsBinaryReader reader) => _reader = reader; + + /// + /// Deserializes a Format 3 (Coverage-based) Chaining Contextual subtable. + /// + /// The absolute byte offset in the stream where the subtable starts. + public ChainingContextualSubstFormat3 Deserialize(long absoluteStart) + { + _reader.BaseStream.Seek(absoluteStart, SeekOrigin.Begin); + var format = _reader.ReadUInt16BigEndian(); + + // Currently, only Format 3 (Coverage-based context) is supported + if (format != 3) return null; + + var table = new ChainingContextualSubstFormat3(); + + // 1. Read Backtrack Coverage offsets + var backtrackCount = _reader.ReadUInt16BigEndian(); + var backtrackOffsets = ReadOffsets(backtrackCount); + + // 2. Read Input Coverage offsets + var inputCount = _reader.ReadUInt16BigEndian(); + var inputOffsets = ReadOffsets(inputCount); + + // 3. Read Lookahead Coverage offsets + var lookaheadCount = _reader.ReadUInt16BigEndian(); + var lookaheadOffsets = ReadOffsets(lookaheadCount); + + // 4. Read Substitution Lookup Records + var substCount = _reader.ReadUInt16BigEndian(); + for (int i = 0; i < substCount; i++) + { + table.SubstLookupRecords.Add(new SubstLookupRecord + { + SequenceIndex = _reader.ReadUInt16BigEndian(), + LookupListIndex = _reader.ReadUInt16BigEndian() + }); + } + + // 5. Load Coverage tables (performed last as offsets are relative to the subtable start) + table.BacktrackCoverages = LoadCoverages(absoluteStart, backtrackOffsets); + table.InputCoverages = LoadCoverages(absoluteStart, inputOffsets); + table.LookaheadCoverages = LoadCoverages(absoluteStart, lookaheadOffsets); + + return table; + } + + private ushort[] ReadOffsets(int count) + { + var offsets = new ushort[count]; + for (int i = 0; i < count; i++) offsets[i] = _reader.ReadUInt16BigEndian(); + return offsets; + } + + private List LoadCoverages(long baseOffset, ushort[] offsets) + { + var list = new List(); + foreach (var offset in offsets) + { + long absolutePos = baseOffset + offset; + _reader.BaseStream.Seek(absolutePos, SeekOrigin.Begin); + + // Read the first two bytes to determine the Coverage table format + ushort format = _reader.ReadUInt16BigEndian(); + + CoverageTable coverage; + if (format == 1) + { + var loader = new CoverageTableFormat1Deserializer(_reader); + coverage = loader.Deserialize(absolutePos); + } + else if (format == 2) + { + var loader = new CoverageTableFormat2Deserializer(_reader); + coverage = loader.Deserialize(absolutePos); + } + else + { + throw new NotSupportedException($"Coverage format {format} is not supported."); + } + + list.Add(coverage); + } + return list; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ExtensionSubstSubTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ExtensionSubstSubTableDeserializer.cs new file mode 100644 index 0000000000..340668b37e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/ExtensionSubstSubTableDeserializer.cs @@ -0,0 +1,57 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + /// + /// Deserializes Extension Substitution subtables (Lookup Type 7). + /// These are used to provide 32-bit offsets to other substitution types when the 16-bit + /// limit of the standard tables is exceeded. + /// + internal class ExtensionSubstSubTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public ExtensionSubstSubTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public FontTableElement Deserialize(long absoluteStart) + { + _reader.BaseStream.Seek(absoluteStart, SeekOrigin.Begin); + + ushort format = _reader.ReadUInt16BigEndian(); // Extension format (must be 1) + ushort lookuptype = _reader.ReadUInt16BigEndian(); // The actual substitution type being extended + uint offset = _reader.ReadUInt32BigEndian(); // 32-bit offset to the actual subtable + + long innerSubTableAbsoluteStart = absoluteStart + offset; + + // Redirect to the appropriate deserializer based on the encapsulated lookup type + switch (lookuptype) + { + case 1: + return new SingleSubstSubTableDeserializer(_reader).Deserialize(innerSubTableAbsoluteStart); + case 4: + return new LigatureSubstSubTableDeserializer(_reader).Deserialize(innerSubTableAbsoluteStart); + case 6: + // Note: We will add the ChainingContextualDeserializer here once implemented + return null; + default: + // Other types can be added here as support grows + return null; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LangSysTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LangSysTableDeserializer.cs new file mode 100644 index 0000000000..155c81df37 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LangSysTableDeserializer.cs @@ -0,0 +1,55 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Scripts; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + internal class LangSysTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public LangSysTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public LangSysTable Deserialize(long langSysTableStartOffset) + { + // Set reader position to the start of the LangSysTable + _reader.BaseStream.Seek(langSysTableStartOffset, SeekOrigin.Begin); + + LangSysTable table = new LangSysTable(); + + // 1. USHORT LookupOrder (Reserved, set to 0) + table.LookupOrder = _reader.ReadUInt16BigEndian(); + + // 2. USHORT RequiredFeatureIndex (Index into FeatureList. 0xFFFF if none required) + table.RequiredFeatureIndex = _reader.ReadUInt16BigEndian(); + + // 3. USHORT FeatureIndexCount + ushort count = _reader.ReadUInt16BigEndian(); + table.FeatureIndexCount = count; // Property only exists for deserialization tracking/debugging + + // 4. USHORT[] FeatureIndices + table.FeatureIndices = new ushort[count]; + for (int i = 0; i < count; i++) + { + // Read USHORT FeatureIndex + table.FeatureIndices[i] = _reader.ReadUInt16BigEndian(); + } + + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSetTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSetTableDeserializer.cs new file mode 100644 index 0000000000..7bd1f5a81d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSetTableDeserializer.cs @@ -0,0 +1,64 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + internal class LigatureSetTableDeserializer + { + private readonly FontsBinaryReader _reader; + private readonly LigatureTableDeserializer _ligatureTableDeserializer; + + public LigatureSetTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + _ligatureTableDeserializer = new LigatureTableDeserializer(reader); + } + + public LigatureSetTable Deserialize(long ligSetStartOffset) + { + _reader.BaseStream.Seek(ligSetStartOffset, SeekOrigin.Begin); + + LigatureSetTable ligSet = new LigatureSetTable(); + + // USHORT LigatureCount + ushort ligCount = _reader.ReadUInt16BigEndian(); + + // USHORT[] LigatureOffsets (relative to LigatureSetTable start) + ushort[] ligOffsets = new ushort[ligCount]; + for (int i = 0; i < ligCount; i++) + { + ligOffsets[i] = _reader.ReadUInt16BigEndian(); + } + + // Save current position after reading offsets + long currentPosition = _reader.BaseStream.Position; + + // Deserialize all LigatureTables + foreach (ushort offset in ligOffsets) + { + // Navigate to LigatureTable: LigatureSetTable Start + Ligature Offset + long ligTableAbsoluteStart = ligSetStartOffset + offset; + + LigatureTable ligTable = _ligatureTableDeserializer.Deserialize(ligTableAbsoluteStart); + ligSet.Ligatures.Add(ligTable); + } + + // Restore position + _reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); + + return ligSet; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSubstSubTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSubstSubTableDeserializer.cs new file mode 100644 index 0000000000..6615b0ff73 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureSubstSubTableDeserializer.cs @@ -0,0 +1,106 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + internal class LigatureSubstSubTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public LigatureSubstSubTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public LigatureSubstSubTable Deserialize(long subTableStartOffset) + { + _reader.BaseStream.Seek(subTableStartOffset, SeekOrigin.Begin); + + LigatureSubstSubTable subTable = new LigatureSubstSubTable(); + + // USHORT SubtableFormat (should be 1 for Format 1) + subTable.SubtableFormat = _reader.ReadUInt16BigEndian(); + + // USHORT CoverageOffset (relative to subTableStartOffset) + ushort coverageOffset = _reader.ReadUInt16BigEndian(); + + // USHORT LigSetCount + ushort ligSetCount = _reader.ReadUInt16BigEndian(); + + // Read LigatureSetOffsets (USHORT array, relative to subTableStartOffset) + ushort[] ligSetOffsets = new ushort[ligSetCount]; + for (int i = 0; i < ligSetCount; i++) + { + ligSetOffsets[i] = _reader.ReadUInt16BigEndian(); + } + + // 1. Deserialize CoverageTable (New logic) + if (coverageOffset > 0) + { + long coverageAbsoluteStart = subTableStartOffset + coverageOffset; + _reader.BaseStream.Seek(coverageAbsoluteStart, SeekOrigin.Begin); + + // Peek at the CoverageFormat to select the correct Deserializer + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + _reader.BaseStream.Seek(coverageAbsoluteStart, SeekOrigin.Begin); // Rewind + + if (coverageFormat == 1) + { + var covDeserializer = new CoverageTableFormat1Deserializer(_reader); + subTable.Coverage = covDeserializer.Deserialize(coverageAbsoluteStart); + } + else if (coverageFormat == 2) + { + var covDeserializer = new CoverageTableFormat2Deserializer(_reader); + subTable.Coverage = covDeserializer.Deserialize(coverageAbsoluteStart); + } + // Handle unsupported formats if necessary + } + + // 2. Deserialize LigatureSetTables + long currentPosition = _reader.BaseStream.Position; + ushort[] coveredGlyphs = subTable.Coverage?.CoveredGlyphs ?? new ushort[0]; // Use new ushort[0] for .NET 3.5 safety + + if (coveredGlyphs.Length != ligSetCount) + { + // Log or handle error: CoverageTable must match LigatureSetCount + } + + var ligSetDeserializer = new LigatureSetTableDeserializer(_reader); // Assuming you create this in the next step + + for (int i = 0; i < ligSetCount; i++) + { + // Navigate to LigatureSetTable: SubTable Start + LigatureSet Offset + long ligSetAbsoluteStart = subTableStartOffset + ligSetOffsets[i]; + + LigatureSetTable ligSet = ligSetDeserializer.Deserialize(ligSetAbsoluteStart); + + // Map LigatureSetTable to the BaseGlyph ID using the index (i) from CoverageTable + if (coveredGlyphs.Length > i) + { + ushort baseGlyphID = coveredGlyphs[i]; + // This assumes LigatureSubstSubTable has a Dictionary property named LigatureSets + subTable.LigatureSets.Add(baseGlyphID, ligSet); + } + } + + // Restore position to after the offset array (optional, but clean) + _reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); + + return subTable; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureTableDeserializer.cs new file mode 100644 index 0000000000..6b317e3191 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/LigatureTableDeserializer.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + internal class LigatureTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public LigatureTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public LigatureTable Deserialize(long startIndex) + { + _reader.BaseStream.Seek(startIndex, SeekOrigin.Begin); + LigatureTable ligTable = new LigatureTable(); + + // USHORT LigatureGlyph (output) + ligTable.LigatureGlyph = _reader.ReadUInt16BigEndian(); + + // USHORT ComponentCount (total glyphs including first) + ushort componentCount = _reader.ReadUInt16BigEndian(); + + // ✅ FIX: Components array has (componentCount - 1) elements + // because first glyph is implicit in LigatureSet + int arrayLength = componentCount - 1; + ligTable.Components = new ushort[arrayLength]; + + for (int i = 0; i < arrayLength; i++) + { + ligTable.Components[i] = _reader.ReadUInt16BigEndian(); + } + + return ligTable; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/SingleSubstSubTableDeserializer.cs b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/SingleSubstSubTableDeserializer.cs new file mode 100644 index 0000000000..92a7386688 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Gsub/IO/SingleSubstSubTableDeserializer.cs @@ -0,0 +1,92 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Coverage.IO; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using System; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Tables.Gsub.IO +{ + internal class SingleSubstSubTableDeserializer + { + private readonly FontsBinaryReader _reader; + + public SingleSubstSubTableDeserializer(FontsBinaryReader reader) + { + _reader = reader; + } + + public SingleSubstSubTable Deserialize(long subTableStartOffset) + { + _reader.BaseStream.Seek(subTableStartOffset, SeekOrigin.Begin); + long currentPos = subTableStartOffset; + + // USHORT SubtableFormat + ushort format = _reader.ReadUInt16BigEndian(); + + // USHORT CoverageOffset + ushort coverageOffset = _reader.ReadUInt16BigEndian(); + + SingleSubstSubTable subTable; + + if (format == 1) + { + subTable = new SingleSubstSubTableFormat1(); + // SSHORT DeltaGlyphID + ((SingleSubstSubTableFormat1)subTable).DeltaGlyphID = _reader.ReadInt16BigEndian(); + } + else if (format == 2) + { + subTable = new SingleSubstSubTableFormat2(); + // USHORT GlyphCount + ushort glyphCount = _reader.ReadUInt16BigEndian(); + ((SingleSubstSubTableFormat2)subTable).GlyphCount = glyphCount; + + // USHORT[] SubstituteGlyphIDs + ((SingleSubstSubTableFormat2)subTable).SubstituteGlyphIDs = new ushort[glyphCount]; + for (int i = 0; i < glyphCount; i++) + { + ((SingleSubstSubTableFormat2)subTable).SubstituteGlyphIDs[i] = _reader.ReadUInt16BigEndian(); + } + } + else + { + throw new NotSupportedException($"Unsupported SingleSubstSubTable format: {format}"); + } + + subTable.SubtableFormat = format; + + // Deserialize CoverageTable + if (coverageOffset > 0) + { + long coverageAbsoluteStart = subTableStartOffset + coverageOffset; + _reader.BaseStream.Seek(coverageAbsoluteStart, SeekOrigin.Begin); + + ushort coverageFormat = _reader.ReadUInt16BigEndian(); + _reader.BaseStream.Seek(coverageAbsoluteStart, SeekOrigin.Begin); + + if (coverageFormat == 1) + { + subTable.Coverage = new CoverageTableFormat1Deserializer(_reader).Deserialize(coverageAbsoluteStart); + } + else if (coverageFormat == 2) + { + subTable.Coverage = new CoverageTableFormat2Deserializer(_reader).Deserialize(coverageAbsoluteStart); + } + } + + _reader.BaseStream.Seek(currentPos, SeekOrigin.Begin); + return subTable; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTable.cs new file mode 100644 index 0000000000..294adffa72 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTable.cs @@ -0,0 +1,185 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Head +{ + /// + /// This table gives global information about the font. + /// + public class HeadTable : FontTableBase + { + public enum IndexToLocFormats : short + { + Offset16 = 0, + Offset32 = 1 + } + + public override string Name => TableNames.Head; + + override public bool IsEssentialTable => true; + + public ushort MajorVersion { get; set; } + + public ushort MinorVersion { get; set; } + + /// + /// Set by font manufacturer. + /// + public int FontRevision { get; set; } + + /// + /// To compute: set it to 0, sum the entire font as uint32,then store 0xB1B0AFBA - sum. + /// If the font is used as acomponent in a font collection file, the value of thisfield + /// will be invalidated by changes to the file structure and font table directory, and must be ignored. + /// + public uint ChecksumAdjustment { get; set; } + + /// + /// Set to 0x5F0F3CF5. + /// + public uint MagicNumber { get; set; } + + public ushort Flags { get; set; } + + /// + /// Set to a value from 16 to 16384. Any value in this range is valid. In fonts that have TrueType outlines, a power of 2 is recommended as this allows performance optimizations in some rasterizers. + /// + public ushort UnitsPerEm { get; set; } + + /// + /// Number of seconds since 12:00 midnight that startedJanuary 1st, 1904, in GMT/UTC time zone. + /// + public long Created { get; set; } + + /// + /// Number of seconds since 12:00 midnight that startedJanuary 1st, 1904, in GMT/UTC time zone. + /// + public long Modified { get; set; } + + /// + /// Minimum x coordinate across all glyph bounding boxes. + /// + public short Xmin { get; set; } + + /// + /// Minimum y coordinate across all glyph bounding boxes. + /// + public short Ymin { get; set; } + + /// + /// Maximum x coordinate across all glyph bounding boxes. + /// + public short Xmax { get; set; } + + /// + /// Maximum y coordinate across all glyph bounding boxes. + /// + public short Ymax { get; set; } + + /// + /// Bit 0: Bold(if set to 1); + /// Bit 1: Italic(if set to 1) + /// Bit 2: Underline(if set to 1) + /// Bit 3: Outline(if set to 1) + /// Bit 4: Shadow(if set to 1) + /// Bit 5: Condensed(if set to 1) + /// Bit 6: Extended(if set to 1) + /// Bits 7 – 15: Reserved(set to 0) + /// + public ushort MacStyle { get; set; } + + /// + /// Smallest readable size in pixels. + /// + public ushort LowestRecPPEM { get; set; } + + /// + /// Deprecated (Set to 2). + /// 0: Fully mixed directional glyphs; + /// 1: Only strongly left to right; + /// 2: Like 1 but also contains neutrals; + /// -1: Only strongly right to left; + /// -2: Like -1 but also contains neutrals. + /// + public short FontDirectionHint { get; set; } + + + /// + /// 0 for short offsets (Offset16), 1 for long (Offset32). + /// + public IndexToLocFormats IndexToLocFormat { get; set; } + + /// + /// 0 for current format. + /// + public short GlyphDataFormat { get; set; } + + public BoundingRectangle GetDefaultBounds() + { + return new BoundingRectangle(Xmin, Ymin, Xmax, Ymax); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + writer.WriteUInt16BigEndian(MajorVersion); + writer.WriteUInt16BigEndian(MinorVersion); + writer.WriteInt32BigEndian(FontRevision); // Fixed32: 16.16 format, men du har int – ev. konvertering behövs + writer.WriteUInt32BigEndian(ChecksumAdjustment); + writer.WriteUInt32BigEndian(MagicNumber); + writer.WriteUInt16BigEndian(Flags); + writer.WriteUInt16BigEndian(UnitsPerEm); + writer.WriteInt64BigEndian(Created); + writer.WriteInt64BigEndian(Modified); + writer.WriteInt16BigEndian(Xmin); + writer.WriteInt16BigEndian(Ymin); + writer.WriteInt16BigEndian(Xmax); + writer.WriteInt16BigEndian(Ymax); + writer.WriteUInt16BigEndian(MacStyle); + writer.WriteUInt16BigEndian(LowestRecPPEM); + writer.WriteInt16BigEndian(FontDirectionHint); + writer.WriteInt16BigEndian((short)IndexToLocFormat); + writer.WriteInt16BigEndian(GlyphDataFormat); + } + + internal override void Clear() + { + throw new System.NotImplementedException(); + } + + public HeadTable Clone() + { + return new HeadTable + { + MajorVersion = this.MajorVersion, + MinorVersion = this.MinorVersion, + FontRevision = this.FontRevision, + ChecksumAdjustment = this.ChecksumAdjustment, + MagicNumber = this.MagicNumber, + Flags = this.Flags, + UnitsPerEm = this.UnitsPerEm, + Created = this.Created, + Modified = this.Modified, + Xmin = this.Xmin, + Ymin = this.Ymin, + Xmax = this.Xmax, + Ymax = this.Ymax, + MacStyle = this.MacStyle, + LowestRecPPEM = this.LowestRecPPEM, + FontDirectionHint = this.FontDirectionHint, + IndexToLocFormat = this.IndexToLocFormat, + GlyphDataFormat = this.GlyphDataFormat + }; + } + } + + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableConstants.cs b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableConstants.cs new file mode 100644 index 0000000000..c6b40e2926 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableConstants.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Head +{ + internal static class HeadTableConstants + { + public const uint MagicNumber = 0x5F0F3CF5; + public const int UnitsPerEmMin = 16; + public const int UnitsPerEmMax = 16384; + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableLoader.cs new file mode 100644 index 0000000000..fb5c6b93cc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableLoader.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Head +{ + internal class HeadTableLoader : TableLoader + { + internal HeadTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Head) + { + } + + protected override HeadTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + var major = _reader.ReadUInt16BigEndian(); + var minor = _reader.ReadUInt16BigEndian(); + var fontRevision = _reader.ReadInt32BigEndian(); + var checksumAdjustment = _reader.ReadUInt32BigEndian(); + var magicNumber = _reader.ReadUInt32BigEndian(); + var flags = _reader.ReadUInt16BigEndian(); + var unitsPerEm = _reader.ReadUInt16BigEndian(); + var createdDate = _reader.ReadInt64BigEndian(); + var modifiedDate = _reader.ReadInt64BigEndian(); + var xMin = _reader.ReadInt16BigEndian(); + var yMin = _reader.ReadInt16BigEndian(); + var xMax = _reader.ReadInt16BigEndian(); + var yMax = _reader.ReadInt16BigEndian(); + var macStyle = _reader.ReadUInt16BigEndian(); + var lowestRecPPEM = _reader.ReadUInt16BigEndian(); + var fontDirectionHint = _reader.ReadInt16BigEndian(); + var indexToLocFormat = _reader.ReadInt16BigEndian(); + return new HeadTable + { + MajorVersion = major, + MinorVersion = minor, + FontRevision = fontRevision, + ChecksumAdjustment = checksumAdjustment, + MagicNumber = magicNumber, + Flags = flags, + UnitsPerEm = unitsPerEm, + Created = createdDate, + Modified = modifiedDate, + Xmin = xMin, + Ymin = yMin, + Xmax = xMax, + Ymax = yMax, + LowestRecPPEM = lowestRecPPEM, + FontDirectionHint = fontDirectionHint, + IndexToLocFormat = (HeadTable.IndexToLocFormats)indexToLocFormat + }; + + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableValidator.cs new file mode 100644 index 0000000000..f864ef9f4a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Head/HeadTableValidator.cs @@ -0,0 +1,97 @@ + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using EPPlus.Fonts.OpenType.FontValidation; + +namespace EPPlus.Fonts.OpenType.Tables.Head +{ + internal class HeadTableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Head; } + } + + public override Type TableType => typeof(HeadTable); + + + public override TableValidationResult Validate(HeadTable table, FontValidationContext context) + { + var result = new TableValidationResult(); + result.TableName = TableName; + + // Magic number + if (table.MagicNumber != HeadTableConstants.MagicNumber) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format($"Invalid magic number: {0:X}. Expected {HeadTableConstants.MagicNumber}.", table.MagicNumber)); + } + + // unitsPerEm range + if (table.UnitsPerEm < HeadTableConstants.UnitsPerEmMin || table.UnitsPerEm > HeadTableConstants.UnitsPerEmMax) + { + result.AddMessage(FontValidationSeverity.Warning, + $"unitsPerEm out of range: {table.UnitsPerEm}. Expected {HeadTableConstants.UnitsPerEmMin}]–{HeadTableConstants.UnitsPerEmMax}."); + } + + // indexToLocFormat + if (table.IndexToLocFormat != HeadTable.IndexToLocFormats.Offset16 && + table.IndexToLocFormat != HeadTable.IndexToLocFormats.Offset32) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("Invalid indexToLocFormat: {0}. Expected Offset16 or Offset32.", table.IndexToLocFormat)); + } + + // Bounding box + if (table.Xmax < table.Xmin) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("xMax ({0}) is less than xMin ({1}).", table.Xmax, table.Xmin)); + } + if (table.Ymax < table.Ymin) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("yMax ({0}) is less than yMin ({1}).", table.Ymax, table.Ymin)); + } + + // Created/Modified dates + if (table.Created < LongDateTimeLimits.MinSeconds || table.Created > LongDateTimeLimits.MaxSeconds) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("Created date seems invalid: {0}.", table.Created)); + } + if (table.Modified < LongDateTimeLimits.MinSeconds || table.Modified > LongDateTimeLimits.MaxSeconds) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("Modified date seems invalid: {0}.", table.Modified)); + } + + if(table.Modified < table.Created) + { + result.AddMessage(FontValidationSeverity.Information, + "Modified LONGDATETIME is earlier than Created LONGDATETIME."); + } + + // Version info + if (table.MajorVersion != 1) + { + result.AddMessage(FontValidationSeverity.Information, + string.Format("Unexpected major version: {0}. Expected 1.", table.MajorVersion)); + } + + return result; + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTable.cs new file mode 100644 index 0000000000..d60c5ae6d8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTable.cs @@ -0,0 +1,148 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Hhea +{ + /// + /// This table contains information for horizontal layout. The values in the minRightSidebearing, + /// minLeftSideBearing and xMaxExtent should be computed using only glyphs that have contours. + /// Glyphs with no contours should be ignored for the purposes of these calculations. All + /// reserved areas must be set to 0. + /// https://docs.microsoft.com/en-us/typography/opentype/spec/hhea + /// + public class HheaTable : FontTableBase + { + public override string Name => TableNames.Hhea; + + public override bool IsEssentialTable => true; + /// + /// Major version number of the horizontal header table — set to 1. + /// + public ushort majorVersion { get; set; } + + /// + /// Minor version number of the horizontal header table — set to 0. + /// + public ushort minorVersion { get; set; } + + /// + /// Typographic ascent + /// + public short ascender { get; set; } + + /// + /// Typographic descent + /// + public short descender { get; set; } + + /// + /// Typographic line gap. + /// Negative LineGap values are treated as zero in some legacy platform implementations. + /// + public short lineGap { get; set; } + + /// + /// Maximum advance width value in 'hmtx' table. + /// + public ushort advanceWidthMax { get; set; } + + /// + /// Minimum left sidebearing value in 'hmtx' table for glyphs with contours (empty glyphs should be ignored). + /// + public short minLeftSideBearing { get; set; } + + /// + /// Minimum right sidebearing value; calculated as min(aw - (lsb + xMax - xMin)) for glyphs with contours (empty glyphs should be ignored). + /// + public short minRightSideBearing { get; set; } + + /// + /// Max(lsb + (xMax - xMin)). + /// + public short xMaxExtent { get; set; } + + /// + /// Used to calculate the slope of the cursor (rise/run); 1 for vertical. + /// + public short caretSlopeRise { get; set; } + + /// + /// 0 for vertical. + /// + public short caretSlopeRun { get; set; } + + /// + /// The amount by which a slanted highlight on a glyph needs to be shifted to produce the best appearance. Set to 0 for non-slanted fonts + /// + public short caretOffset { get; set; } + + /// + /// 0 for current format. + /// + public short metricDataFormat { get; set; } + + /// + /// Number of hMetric entries in 'hmtx' table + /// + public ushort numberOfHMetrics { get; set; } + + internal override void Clear() + { + throw new System.NotImplementedException(); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + writer.WriteUInt16BigEndian(majorVersion); + writer.WriteUInt16BigEndian(minorVersion); + writer.WriteInt16BigEndian(ascender); + writer.WriteInt16BigEndian(descender); + writer.WriteInt16BigEndian(lineGap); + writer.WriteUInt16BigEndian(advanceWidthMax); + writer.WriteInt16BigEndian(minLeftSideBearing); + writer.WriteInt16BigEndian(minRightSideBearing); + writer.WriteInt16BigEndian(xMaxExtent); + writer.WriteInt16BigEndian(caretSlopeRise); + writer.WriteInt16BigEndian(caretSlopeRun); + writer.WriteInt16BigEndian(caretOffset); + writer.WriteInt16BigEndian(0); // reserved1 + writer.WriteInt16BigEndian(0); // reserved2 + writer.WriteInt16BigEndian(0); // reserved3 + writer.WriteInt16BigEndian(0); // reserved4 + writer.WriteInt16BigEndian(metricDataFormat); + writer.WriteUInt16BigEndian(numberOfHMetrics); + } + + + public HheaTable Clone() + { + return new HheaTable + { + majorVersion = this.majorVersion, + minorVersion = this.minorVersion, + ascender = this.ascender, + descender = this.descender, + lineGap = this.lineGap, + advanceWidthMax = this.advanceWidthMax, + minLeftSideBearing = this.minLeftSideBearing, + minRightSideBearing = this.minRightSideBearing, + xMaxExtent = this.xMaxExtent, + caretSlopeRise = this.caretSlopeRise, + caretSlopeRun = this.caretSlopeRun, + caretOffset = this.caretOffset, + metricDataFormat = this.metricDataFormat, + numberOfHMetrics = this.numberOfHMetrics + }; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableConstants.cs b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableConstants.cs new file mode 100644 index 0000000000..96986cf65c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableConstants.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Hhea +{ + internal static class HheaTableConstants + { + public const int ExpectedMajorVersion = 1; + + public const int ExpectedMinorVersion = 0; + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableLoader.cs new file mode 100644 index 0000000000..bb2b70d3ec --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableLoader.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Hhea +{ + internal class HheaTableLoader : TableLoader + { + public HheaTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Hhea) + { + } + + protected override HheaTable LoadInternal() + { + var majorVersion = _reader.ReadUInt16BigEndian(); + var minorVersion = _reader.ReadUInt16BigEndian(); + var ascender = _reader.ReadInt16BigEndian(); + var descender = _reader.ReadInt16BigEndian(); + var lineGap = _reader.ReadInt16BigEndian(); + var advanceWidthMax = _reader.ReadUInt16BigEndian(); + var minLeftSideBearing = _reader.ReadInt16BigEndian(); + var minRightSideBearing = _reader.ReadInt16BigEndian(); + var xMaxExtent = _reader.ReadInt16BigEndian(); + var caretSlopeRise = _reader.ReadInt16BigEndian(); + var caretSlopeRun = _reader.ReadInt16BigEndian(); + var caretOffset = _reader.ReadInt16BigEndian(); + var reserved1 = _reader.ReadInt16BigEndian(); + var reserved2 = _reader.ReadInt16BigEndian(); + var reserved3 = _reader.ReadInt16BigEndian(); + var reserved4 = _reader.ReadInt16BigEndian(); + var metricDataFormat = _reader.ReadInt16BigEndian(); + var numberOfHMetrics = _reader.ReadUInt16BigEndian(); + + return new HheaTable + { + majorVersion = majorVersion, + minorVersion = minorVersion, + ascender = ascender, + descender = descender, + lineGap = lineGap, + advanceWidthMax = advanceWidthMax, + minLeftSideBearing = minLeftSideBearing, + minRightSideBearing = minRightSideBearing, + xMaxExtent = xMaxExtent, + caretSlopeRise = caretSlopeRise, + caretSlopeRun = caretSlopeRun, + caretOffset = caretOffset, + metricDataFormat = metricDataFormat, + numberOfHMetrics = numberOfHMetrics + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableValidator.cs new file mode 100644 index 0000000000..1fa6db6790 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hhea/HheaTableValidator.cs @@ -0,0 +1,146 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Hhea +{ + internal class HheaTableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Hhea; } + } + + public override Type TableType => typeof(HheaTable); + + + public override TableValidationResult Validate(HheaTable table, FontValidationContext context) + { + var result = new TableValidationResult(); + result.TableName = TableName; + + + // Rule 1: Version check with tolerant strategy + if (table.majorVersion == HheaTableConstants.ExpectedMajorVersion && + table.minorVersion == HheaTableConstants.ExpectedMinorVersion) + { + // Expected version (e.g., 1.0) - OK + } + else if (table.majorVersion == 0 && table.minorVersion == 0) + { + // Older TrueType fonts sometimes have 0.0 - tolerate but warn + result.AddMessage(FontValidationSeverity.Warning, + string.Format("Version is {0}.{1}. Expected {2}.{3}, but 0.0 is tolerated for older fonts.", + table.majorVersion, + table.minorVersion, + HheaTableConstants.ExpectedMajorVersion, + HheaTableConstants.ExpectedMinorVersion)); + } + else + { + // Any other version is considered invalid + result.AddMessage(FontValidationSeverity.Error, + string.Format("Invalid version: {0}.{1}. Expected {2}.{3}.", + table.majorVersion, + table.minorVersion, + HheaTableConstants.ExpectedMajorVersion, + HheaTableConstants.ExpectedMinorVersion)); + } + + + // Rule 2: Ascender and Descender should not be zero + if (table.ascender == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "ascender is 0, which is unusual."); + } + if (table.descender == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "descender is 0, which is unusual."); + } + + // Rule 3: lineGap can be negative but usually >= 0 + if (table.lineGap < 0) + { + result.AddMessage(FontValidationSeverity.Information, + string.Format("lineGap is negative ({0}). Some platforms treat negative as zero.", table.lineGap)); + } + + // Rule 4: advanceWidthMax should be > 0 + if (table.advanceWidthMax == 0) + { + result.AddMessage(FontValidationSeverity.Error, "advanceWidthMax is 0, which is invalid."); + } + + + if (table.advanceWidthMax > context.Font.HeadTable.UnitsPerEm * 2) + { + result.AddMessage(FontValidationSeverity.Warning, + $"advanceWidthMax ({table.advanceWidthMax}) seems unusually large compared to HeadTable.UnitsPerEm ({context.Font.HeadTable.UnitsPerEm})."); + } + + + // Rule 5: metricDataFormat must be 0 + if (table.metricDataFormat != 0) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("metricDataFormat is {0}. Expected 0.", table.metricDataFormat)); + } + + // Rule 6: numberOfHMetrics should be > 0 + if (table.numberOfHMetrics == 0) + { + result.AddMessage(FontValidationSeverity.Error, "numberOfHMetrics is 0, which is invalid."); + } + + // Optional: caretSlopeRise and caretSlopeRun checks + if (table.caretSlopeRise == 0 && table.caretSlopeRun == 0) + { + result.AddMessage(FontValidationSeverity.Information, + "caretSlopeRise and caretSlopeRun are both 0. Expected rise=1 for vertical caret."); + } + + + // Check numberOfHMetrics against hmtx + int hmtxCount = context.Font.HmtxTable?.hMetrics.Count ?? 0; + if (hmtxCount != table.numberOfHMetrics) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hhea: numberOfHMetrics ({table.numberOfHMetrics}) does not match hmtx.hMetrics.Count ({hmtxCount})."); + } + + // Check numberOfHMetrics ≤ numGlyphs + int numGlyphs = context.Font.MaxpTable.numGlyphs; + if (table.numberOfHMetrics > numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hhea: numberOfHMetrics ({table.numberOfHMetrics}) exceeds maxp.numGlyphs ({numGlyphs})."); + } + + // Check advanceWidthMax against hmtx + if (context.Font.HmtxTable != null) + { + ushort maxAdvanceWidthInHmtx = context.Font.HmtxTable.hMetrics.Max(m => m.advanceWidth); + if (table.advanceWidthMax < maxAdvanceWidthInHmtx) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hhea: advanceWidthMax ({table.advanceWidthMax}) is less than max advanceWidth in hmtx ({maxAdvanceWidthInHmtx})."); + } + } + + + return result; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTable.cs new file mode 100644 index 0000000000..4c0eedb5be --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTable.cs @@ -0,0 +1,174 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Hmtx +{ + /// + /// Glyph metrics used for horizontal text layout include glyph advance widths, side bearings + /// and X-direction min and max values (xMin, xMax). These are derived using a combination of + /// the glyph outline data ('glyf', 'CFF ' or CFF2) and the horizontal metrics table. The horizontal + /// metrics ('hmtx') table provides glyph advance widths and left side bearings. + /// https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx + /// + public class HmtxTable : FontTableBase + { + public override string Name => TableNames.Hmtx; + + public override bool IsEssentialTable => false; + public List hMetrics { get; set; } = new List(); + public List leftSideBearings { get; set; } = new List(); + + public HmtxTable() + { + + } + + public HmtxTable(List metrics) + { + hMetrics = metrics; + } + + internal override void Clear() + { + hMetrics.Clear(); + leftSideBearings.Clear(); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + foreach (var metric in hMetrics) + { + writer.WriteUInt16BigEndian(metric.advanceWidth); + writer.WriteInt16BigEndian(metric.lsb); + } + + foreach (var lsb in leftSideBearings) + { + writer.WriteInt16BigEndian(lsb); + } + } + + + public HmtxTable CloneSubset(HashSet glyphSet, HmtxTable original) + { + var newTable = new HmtxTable(); + + // Sort glyphs för stabilitet + var sortedGlyphs = glyphSet.OrderBy(g => g).ToList(); + + foreach (var glyphId in sortedGlyphs) + { + if (glyphId < original.hMetrics.Count) + { + // Glyph har en full metric-post + var metric = original.hMetrics[glyphId]; + newTable.hMetrics.Add(new LongHorMetric + { + advanceWidth = metric.advanceWidth, + lsb = metric.lsb + }); + } + else + { + // Glyph ligger utanför hMetrics -> hämta från leftSideBearings + int lsbIndex = glyphId - original.hMetrics.Count; + short lsbValue = (lsbIndex < original.leftSideBearings.Count) + ? original.leftSideBearings[lsbIndex] + : (short)0; + + newTable.hMetrics.Add(new LongHorMetric + { + advanceWidth = original.hMetrics.Last().advanceWidth, // enligt spec + lsb = lsbValue + }); + } + } + + return newTable; + } + + internal HmtxTable CloneForGlyphCount(int newGlyphCount, int originalGlyphCount) + { + var clone = new HmtxTable(); + + int originalHMetricsCount = this.hMetrics.Count; + int originalLsbCount = this.leftSideBearings.Count; + + // hMetrics måste alltid ha newGlyphCount entries + clone.hMetrics = new List(newGlyphCount); + + // leftSideBearings får max newGlyphCount - originalHMetricsCount + int neededLsbCount = Math.Max(0, newGlyphCount - originalHMetricsCount); + clone.leftSideBearings = new List(neededLsbCount); + + // Kopiera hMetrics + int copyHMetrics = Math.Min(newGlyphCount, originalHMetricsCount); + for (int i = 0; i < copyHMetrics; i++) + { + clone.hMetrics.Add(new LongHorMetric + { + advanceWidth = this.hMetrics[i].advanceWidth, + lsb = this.hMetrics[i].lsb + }); + } + + // Fyll på hMetrics med sista advanceWidth + if (newGlyphCount > copyHMetrics) + { + var last = this.hMetrics[originalHMetricsCount - 1]; + for (int i = copyHMetrics; i < newGlyphCount; i++) + { + clone.hMetrics.Add(new LongHorMetric + { + advanceWidth = last.advanceWidth, + lsb = 0 + }); + } + } + + // Kopiera befintliga LSB + int copyLsb = Math.Min(neededLsbCount, originalLsbCount); + for (int i = 0; i < copyLsb; i++) + { + clone.leftSideBearings.Add(this.leftSideBearings[i]); + } + + // Fyll på med 0:or om vi har fler glyphs + while (clone.leftSideBearings.Count < neededLsbCount) + { + clone.leftSideBearings.Add(0); + } + + return clone; + } + + public ushort GetAdvanceWidth(int glyphIndex) + { + if (glyphIndex < hMetrics.Count) + return hMetrics[glyphIndex].advanceWidth; + return hMetrics[hMetrics.Count - 1].advanceWidth; // fallback + } + + public short GetLeftSideBearing(int glyphIndex) + { + if (glyphIndex < hMetrics.Count) + return hMetrics[glyphIndex].lsb; + if (glyphIndex < leftSideBearings.Count) + return leftSideBearings[glyphIndex - hMetrics.Count]; + return 0; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableLoader.cs new file mode 100644 index 0000000000..9e611c3bc5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableLoader.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Hmtx +{ + internal class HmtxTableLoader : TableLoader + { + private TableLoaderSettings tableLoaderSettingsRef; + public HmtxTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Hmtx) + { + tableLoaderSettingsRef = settings; + } + + protected override HmtxTable LoadInternal() + { + var hheaTable = TableLoaders.GetHheaTableLoader(tableLoaderSettingsRef).Load(); + var maxpTable = TableLoaders.GetMaxpTableLoader(tableLoaderSettingsRef).Load(); + _reader.BaseStream.Position = _offset; + var metrics = new List(); + for(var x = 0; x < hheaTable.numberOfHMetrics; x++) + { + var metric = new LongHorMetric + { + advanceWidth = _reader.ReadUInt16BigEndian(), + lsb = _reader.ReadInt16BigEndian() + }; + metrics.Add(metric); + } + var bearings = new List(); + for(var x = 0; x < (maxpTable.numGlyphs - hheaTable.numberOfHMetrics); x++) + { + var b = _reader.ReadInt16BigEndian(); + bearings.Add(b); + } + return new HmtxTable + { + hMetrics = metrics, + leftSideBearings = bearings + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableValidator.cs new file mode 100644 index 0000000000..b5811f897c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/HmtxTableValidator.cs @@ -0,0 +1,107 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Hmtx +{ + + internal class HmtxTableValidator : TableValidatorBase + { + public override Type TableType => typeof(HmtxTable); + public override string TableName => "hmtx"; + + public override TableValidationResult Validate(HmtxTable hmtx, FontValidationContext context) + { + var result = new TableValidationResult(); + result.TableName = TableName; + var font = context.Font; + + int numGlyphs = font.MaxpTable.numGlyphs; + int numHMetrics = font.HheaTable.numberOfHMetrics; + + // 1. Validate hMetrics count + if (hmtx.hMetrics.Count != numHMetrics) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: Expected {numHMetrics} hMetrics entries (from hhea), found {hmtx.hMetrics.Count}."); + } + + // 2. Validate total coverage + int totalEntries = hmtx.hMetrics.Count + hmtx.leftSideBearings.Count; + if (totalEntries < numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: Total entries ({totalEntries}) do not cover all glyphs ({numGlyphs})."); + } + + // 3. Validate advance widths + for (int i = 0; i < hmtx.hMetrics.Count; i++) + { + ushort aw = hmtx.hMetrics[i].advanceWidth; + if (aw == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Hmtx: advanceWidth for glyph {i} is 0 (may be intentional, but check)."); + } + } + + // 4. Validate LSB values + foreach (var metric in hmtx.hMetrics) + { + if (metric.lsb < -32768 || metric.lsb > 32767) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: LSB value {metric.lsb} out of valid range (-32768 to 32767)."); + } + } + + foreach (var lsb in hmtx.leftSideBearings) + { + if (lsb < -32768 || lsb > 32767) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: LSB value {lsb} out of valid range (-32768 to 32767)."); + } + } + + + // 5. Check advanceWidth against hhea.advanceWidthMax + ushort maxAdvanceWidth = font.HheaTable.advanceWidthMax; + for (int i = 0; i < hmtx.hMetrics.Count; i++) + { + ushort aw = hmtx.hMetrics[i].advanceWidth; + if (aw > maxAdvanceWidth) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: advanceWidth for glyph {i} ({aw}) exceeds hhea.advanceWidthMax ({maxAdvanceWidth})."); + } + } + + // 6. Check that extra LSBs cover the remaining glyphs correctly + int expectedExtraLSBs = numGlyphs - numHMetrics; + if (hmtx.leftSideBearings.Count != expectedExtraLSBs) + { + result.AddMessage(FontValidationSeverity.Error, + $"Hmtx: Expected {expectedExtraLSBs} extra LSBs, found {hmtx.leftSideBearings.Count}."); + } + + + return result; + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Hmtx/LongHorMetric.cs b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/LongHorMetric.cs new file mode 100644 index 0000000000..aeb17b53e2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Hmtx/LongHorMetric.cs @@ -0,0 +1,32 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Hmtx +{ + public class LongHorMetric + { + /// + /// Advance width, in font design units. + /// + public ushort advanceWidth{ get; set; } + + /// + /// Glyph left side bearing, in font design units. + /// + public short lsb { get; set; } + + public override string ToString() + { + return $"advanceWidth: {advanceWidth}, lsb: {lsb}"; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KernCoverage.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernCoverage.cs new file mode 100644 index 0000000000..c27b690636 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernCoverage.cs @@ -0,0 +1,138 @@ +using System; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + + public class KernCoverage + { + public ushort RawValue { get; } + + internal KernCoverage(FontsBinaryReader reader) + { + RawValue = reader.ReadUInt16BigEndian(); + } + /// + /// true if table has horizontal data, false if vertical. + /// + public bool Horizontal => (RawValue & 0x1) != 0; + public bool Minimum => ((RawValue >> 1) & 0x1) != 0; + /// + /// If set to 1, kerning is perpendicular to the flow of the text. + /// + /// If the text is normally written horizontally, kerning will be done + /// in the up and down directions. If kerning values are positive, the + /// text will be kerned upwards; if they are negative, the text will be + /// kerned downwards. + /// + /// If the text is normally written vertically, kerning will be done in + /// the left and right directions. If kerning values are positive, the + /// text will be kerned to the right; if they are negative, the text will + /// be kerned to the left. + /// + /// The value 0x8000 in the kerning data resets the cross-stream kerning back to 0. + /// + public bool CrossStream => ((RawValue >> 2) & 0x1) != 0; + /// + /// If true the value in this table should replace the value + /// currently being accumulated. + /// + public bool Override => ((RawValue >> 3) & 0x1) != 0; + public bool ReservedBitsAreZero => ((RawValue >> 4) & 0xF) == 0; + /// + /// Format of the subtable. Only formats 0 and 2 have been defined. + /// Formats 1 and 3 through 255 are reserved for future use. + /// + public byte Format => (byte)(RawValue >> 8); + + internal void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(RawValue); + } + } + + + public class KernCoverage2 + { + internal KernCoverage2(FontsBinaryReader reader) + { + _coverage = reader.ReadUInt16BigEndian(); + } + + public ushort _coverage; + + /// + /// true if table has horizontal data, false if vertical. + /// + public bool horizontal + { + get + { + return (_coverage & 0x1) == 1; + } + } + + /// + /// + /// + public bool minimum + { + get + { + return ((_coverage >> 1) & 0x1) == 1; + } + } + + /// + /// If set to 1, kerning is perpendicular to the flow of the text. + /// + /// If the text is normally written horizontally, kerning will be done + /// in the up and down directions. If kerning values are positive, the + /// text will be kerned upwards; if they are negative, the text will be + /// kerned downwards. + /// + /// If the text is normally written vertically, kerning will be done in + /// the left and right directions. If kerning values are positive, the + /// text will be kerned to the right; if they are negative, the text will + /// be kerned to the left. + /// + /// The value 0x8000 in the kerning data resets the cross-stream kerning back to 0. + /// + public bool crossStream + { + get + { + return ((_coverage >> 2) & 0x1) == 1; + } + } + + /// + /// If true the value in this table should replace the value + /// currently being accumulated. + /// + public bool Override + { + get + { + return ((_coverage >> 3) & 0x1) == 1; + } + } + + /// + /// Format of the subtable. Only formats 0 and 2 have been defined. + /// Formats 1 and 3 through 255 are reserved for future use. + /// + public byte Format => (byte)(_coverage >> 8); + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTable.cs new file mode 100644 index 0000000000..7f695d358e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTable.cs @@ -0,0 +1,55 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + public class KernSubTable : FontTableElement + { + public ushort version { get; set; } + + public ushort length { get; set; } + + public KernCoverage coverage { get; set; } + + public KernSubTableFormat0 Format0Subtable { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + // Temp stream to calculate table length + using var ms = new MemoryStream(); + using var tempWriter = new FontsBinaryWriter(ms); + + if (coverage.Format == 0 && Format0Subtable != null) + { + Format0Subtable.Serialize(tempWriter); + } + else + { + throw new NotSupportedException($"Unsupported kern subtable format: {coverage.Format}"); + } + + byte[] subtableData = ms.ToArray(); + length = (ushort)(subtableData.Length + 6); // 6 bytes for version, length, coverage + + // Write subtable-header + writer.WriteUInt16BigEndian(version); + writer.WriteUInt16BigEndian(length); + writer.WriteUInt16BigEndian(coverage.RawValue); + + // Then write subtable-data + writer.Write(subtableData); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTableFormat0.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTableFormat0.cs new file mode 100644 index 0000000000..eec7af7e97 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernSubTableFormat0.cs @@ -0,0 +1,67 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + public class KernSubTableFormat0 : FontTableElement + { + internal KernSubTableFormat0(FontsBinaryReader reader) + { + if(reader != null) + { + nPairs = reader.ReadUInt16BigEndian(); + SearchRange = reader.ReadUInt16BigEndian(); + EntrySelector = reader.ReadUInt16BigEndian(); + RangeShift = reader.ReadUInt16BigEndian(); + } + } + + public ushort nPairs { get; set; } + + public ushort SearchRange { get; set; } + public ushort EntrySelector { get; set; } + public ushort RangeShift { get; set; } + + public KerningPair[] Pairs { get; set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + + + writer.WriteUInt16BigEndian(nPairs); + + // Beräkna sökparametrar + ushort maxPowerOf2 = 1; + while (maxPowerOf2 * 2 <= nPairs) + maxPowerOf2 *= 2; + + ushort searchRange = (ushort)(maxPowerOf2 * 6); + ushort entrySelector = (ushort)(Math.Log(maxPowerOf2) / Math.Log(2)); + ushort rangeShift = (ushort)((nPairs * 6) - searchRange); + + writer.WriteUInt16BigEndian(searchRange); + writer.WriteUInt16BigEndian(entrySelector); + writer.WriteUInt16BigEndian(rangeShift); + + // Skriv kerningpar + foreach (var pair in Pairs) + { + writer.WriteUInt16BigEndian(pair.left); + writer.WriteUInt16BigEndian(pair.right); + writer.WriteInt16BigEndian(pair.value); + } + + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTable.cs new file mode 100644 index 0000000000..81375dee48 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTable.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + public class KernTable : FontTableBase + { + public override string Name => TableNames.Kern; + + public override bool IsEssentialTable => false; + + public ushort version { get; set; } + public ushort numberOfFormat0Tables { get; set; } + + public List SubTables { get; set; } = new List(); + + internal override void Clear() + { + SubTables.Clear(); + version = 0; + numberOfFormat0Tables = 0; + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + writer.WriteUInt16BigEndian(version); + writer.WriteUInt16BigEndian((ushort)SubTables.Count); + + foreach (var subTable in SubTables) + { + subTable.Serialize(writer); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTableLoader.cs new file mode 100644 index 0000000000..17ad3eb53d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KernTableLoader.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + internal class KernTableLoader : TableLoader + { + public KernTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Kern) + { + } + + protected override KernTable LoadInternal() + { + var v = _reader.ReadUInt16BigEndian(); + var nt = _reader.ReadUInt16BigEndian(); + var table = new KernTable + { + version = v, + numberOfFormat0Tables = Convert.ToUInt16(nt) + }; + var subTables = new List(); + var nextTablePos = _reader.BaseStream.Position; + ushort nPairs = 0; + for (var x = 0; x < table.numberOfFormat0Tables; x++) + { + var subTable = new KernSubTable + { + version = _reader.ReadUInt16BigEndian(), + length = _reader.ReadUInt16BigEndian(), + coverage = new KernCoverage(_reader) + }; + nextTablePos += subTable.length; + if(subTable.coverage.Format == 0) + { + var format0Table = new KernSubTableFormat0(_reader); + if (format0Table.nPairs > 0) + { + var pairs = new KerningPair[format0Table.nPairs]; + for(var pIx = 0; pIx < format0Table.nPairs; pIx++) + { + pairs[pIx] = new KerningPair(_reader); + nPairs++; + } + format0Table.Pairs = pairs; + } + subTable.Format0Subtable = format0Table; + subTables.Add(subTable); + } + _reader.BaseStream.Position = nextTablePos; + } + table.SubTables = subTables; + table.numberOfFormat0Tables = nPairs; + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Kern/KerningPair.cs b/src/EPPlus.Fonts.OpenType/Tables/Kern/KerningPair.cs new file mode 100644 index 0000000000..7723c1ea2a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Kern/KerningPair.cs @@ -0,0 +1,58 @@ +using System; +using System.Diagnostics; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Kern +{ + [DebuggerDisplay("l: {left}, r: {right}, v: {value}")] + public class KerningPair + { + internal KerningPair(FontsBinaryReader reader) + { + if(reader != null) + { + left = reader.ReadUInt16BigEndian(); + right = reader.ReadUInt16BigEndian(); + value = reader.ReadInt16BigEndian(); + //Left is high-order/most significant + //but since big-endian we must do it like this. + Combined = ((uint)left << 16) | right; + } + } + + /// + /// Glyph-index for left glyph + /// + public ushort left { get; set; } + + /// + /// Glyph-index for right glyph + /// + public ushort right { get; set; } + /// + /// FWORD in font-design units. + /// Negative value moves chars closer + /// Positive value moves chars further apart + /// + public short value { get; set; } + + /// + /// The pairs are ordered in numeric order based on the combinded uint32 value of left and right. + /// (left is high order word) + /// Therefore useful in binary search later to have this number readily available + /// Source: https://learn.microsoft.com/en-us/typography/opentype/spec/kern#format-0 + /// + public uint Combined { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTable.cs new file mode 100644 index 0000000000..24020013dd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTable.cs @@ -0,0 +1,111 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Loca +{ + /// + /// The indexToLoc table stores the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table + /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca + /// + public class LocaTable : FontTableBase + { + // TA BORT HELT: private readonly MaxpTable _maxpTable; + + public LocaTable() + { + } + + public override string Name => TableNames.Loca; + public override bool IsEssentialTable => true; + + public List Offsets { get; set; } = new List(); + public HeadTable.IndexToLocFormats IndexToLocFormat { get; set; } + + internal override void Clear() + { + Offsets.Clear(); + } + + internal int GetGlyphCountSafe() + { + if (Offsets == null || Offsets.Count < 2) + return 0; + + return Offsets.Count - 1; + } + + // ENDA factoryn – ingen Maxp-referens längre + internal static LocaTable CreateSubset(List offsets, HeadTable.IndexToLocFormats indexToLocFormat) + { + return new LocaTable + { + Offsets = new List(offsets), // defensiv kopia + IndexToLocFormat = indexToLocFormat + }; + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + if (Offsets == null || Offsets.Count == 0) + throw new InvalidOperationException("Offsets list cannot be null or empty."); + + // NYTT: Hämta numGlyphs från fonten (via context) istället för intern referens + int expectedCount = context.Font?.MaxpTable?.numGlyphs + 1 ?? Offsets.Count; + + if (Offsets.Count != expectedCount) + { + // VIKTIGT: För subset är detta OK ibland (t.ex. under byggande) + // Men vi loggar bara – kastar inte i subset-läge + if (context.IsSubsetInProgress != true) + { + throw new InvalidOperationException( + $"Offsets count ({Offsets.Count}) does not match expected numGlyphs + 1 ({expectedCount})."); + } + } + + // Resten oförändrad – perfekt som den är + for (int i = 1; i < Offsets.Count; i++) + { + if (Offsets[i] < Offsets[i - 1]) + throw new InvalidOperationException("Offsets must be in ascending order."); + } + + if (IndexToLocFormat == HeadTable.IndexToLocFormats.Offset16) + { + foreach (var offset in Offsets) + { + if (offset > 0x1FFFF) + throw new InvalidOperationException($"Offset {offset} exceeds maximum for Offset16 format."); + + ushort shortOffset = (ushort)(offset / 2); + writer.WriteUInt16BigEndian(shortOffset); + } + } + else if (IndexToLocFormat == HeadTable.IndexToLocFormats.Offset32) + { + foreach (var offset in Offsets) + { + writer.WriteUInt32BigEndian(offset); + } + } + else + { + throw new InvalidOperationException($"Unsupported IndexToLocFormat: {IndexToLocFormat}"); + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableLoader.cs new file mode 100644 index 0000000000..177a835125 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableLoader.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Head; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Loca +{ + internal class LocaTableLoader : TableLoader + { + private TableLoaderSettings LoadingSettingsRef; + + public LocaTableLoader(TableLoaderSettings tblSettings) : base(tblSettings, TableNames.Loca) + { + LoadingSettingsRef = tblSettings; + } + + protected override LocaTable LoadInternal() + { + var headTable = TableLoaders.GetHeadTableLoader(LoadingSettingsRef).Load(); + var maxpTable = TableLoaders.GetMaxpTableLoader(LoadingSettingsRef).Load(); + _reader.BaseStream.Position = _offset; + var indexes = new List(); + if(headTable.IndexToLocFormat == HeadTable.IndexToLocFormats.Offset16) + { + for(var x = 0; x < maxpTable.numGlyphs + 1; x++) + { + var ix = Convert.ToUInt32(_reader.ReadUInt16BigEndian()); + ix *= 2; + indexes.Add(ix); + } + } + else if(headTable.IndexToLocFormat == HeadTable.IndexToLocFormats.Offset32) + { + for(var x = 0; x < maxpTable.numGlyphs + 1; x++) + { + var ix = _reader.ReadUInt32BigEndian(); + indexes.Add(ix); + } + } + return new LocaTable() + { + Offsets = indexes, + IndexToLocFormat = headTable.IndexToLocFormat + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableValidator.cs new file mode 100644 index 0000000000..e066eed997 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Loca/LocaTableValidator.cs @@ -0,0 +1,117 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using EPPlus.Fonts.OpenType.Tables.Head; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Loca +{ + + internal class LocaTableValidator : TableValidatorBase + { + public override Type TableType => typeof(LocaTable); + public override string TableName => "loca"; + + public override TableValidationResult Validate(LocaTable loca, FontValidationContext context) + { + var result = new TableValidationResult(); + result.TableName = TableName; + var font = context.Font; + + // 1. Check that offsets count matches numGlyphs + 1 + int expectedCount = font.MaxpTable.numGlyphs + 1; + if (loca.Offsets.Count != expectedCount) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: Expected {expectedCount} offsets (numGlyphs + 1), found {loca.Offsets.Count}."); + } + + // 2. Validate IndexToLocFormat + if (loca.IndexToLocFormat != HeadTable.IndexToLocFormats.Offset16 && + loca.IndexToLocFormat != HeadTable.IndexToLocFormats.Offset32) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: Invalid IndexToLocFormat {loca.IndexToLocFormat}. Must be Offset16 or Offset32."); + } + + var glyfTableLength = font.GlyfTable.GetLength(font); + + // 3. Validate offsets ascending and glyph lengths + for (int i = 0; i < loca.Offsets.Count - 1; i++) + { + uint current = loca.Offsets[i]; + uint next = loca.Offsets[i + 1]; + + if (next < current) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: Offset[{i}] ({current}) > Offset[{i + 1}] ({next}). Offsets must be ascending."); + } + + uint glyphLength = next - current; + if (glyphLength > glyfTableLength) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Loca: Glyph {i} length {glyphLength} exceeds glyf table size ({glyfTableLength})."); + } + } + + // 4. Validate all offsets within glyf table bounds + foreach (var offset in loca.Offsets) + { + if (offset > glyfTableLength) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: Offset {offset} exceeds glyf table length ({glyfTableLength})."); + } + + // Additional check for Offset16 format + if (loca.IndexToLocFormat == HeadTable.IndexToLocFormats.Offset16 && offset > 0x1FFFF) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: Offset {offset} exceeds maximum allowed for Offset16 format (131072 bytes)."); + } + } + + // 5. Optional: Warn if glyf table is empty but offsets > 0 + if (glyfTableLength == 0 && loca.Offsets.Any(o => o > 0)) + { + result.AddMessage(FontValidationSeverity.Warning, + "Loca: Glyf table is empty but offsets contain non-zero values."); + } + + + // 6. Check that IndexToLocFormat in loca matches the head table + if (loca.IndexToLocFormat != font.HeadTable.IndexToLocFormat) + { + result.AddMessage(FontValidationSeverity.Error, + $"Loca: IndexToLocFormat mismatch with head table. Expected {font.HeadTable.IndexToLocFormat}, found {loca.IndexToLocFormat}."); + } + + // 7. Check that the last offset ≈ the end of the glyf table + uint lastOffset = loca.Offsets.Last(); + if (lastOffset != glyfTableLength) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Loca: Last offset ({lastOffset}) does not match glyf table length ({glyfTableLength})."); + } + + + return result; + } + } + +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTable.cs new file mode 100644 index 0000000000..c4a34a5953 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTable.cs @@ -0,0 +1,135 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Maxp +{ + public class MaxpTable : FontTableBase + { + public override string Name => TableNames.Maxp; + + public override bool IsEssentialTable => true; + /// + /// 0x00005000 for version 0.5 + /// 0x00010000 for version 1.0. + /// + public Version16Dot16 version { get; set; } + + /// + /// The number of glyphs in the font. + /// + public ushort numGlyphs { get; set; } + + /// + /// Maximum points in a non-composite glyph. + /// + public ushort maxPoints { get; set; } + + /// + /// Maximum contours in a non-composite glyph. + /// + public ushort maxContours { get; set; } + + /// + /// Maximum points in a composite glyph. + /// + public ushort maxCompositePoints { get; set; } + + /// + /// Maximum contours in a composite glyph. + /// + public ushort maxCompositeContours { get; set; } + + /// + /// 1 if instructions do not use the twilight zone (Z0), or + /// 2 if instructions do use Z0; should be set to 2 in + /// most cases. + /// + public ushort maxZones { get; set; } + + /// + /// Maximum points used in Z0. + /// + public ushort maxTwilightPoints { get; set; } + + /// + /// Number of Storage Area locations. + /// + public ushort maxStorage { get; set; } + + /// + /// Number of FDEFs, equal to the highest function number + 1. + /// + public ushort maxFunctionDefs { get; set; } + + /// + /// Number of IDEFs. + /// + public ushort maxInstructionDefs { get; set; } + + public ushort maxStackElements { get; set; } + + public ushort maxSizeOfInstructions { get; set; } + + public ushort maxComponentElements { get; set; } + + public ushort maxComponentDepth { get; set; } + + internal override void Clear() + { + throw new System.NotImplementedException(); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + version.Serialize(writer); + writer.WriteUInt16BigEndian(numGlyphs); + if(version.Major == 1) + { + writer.WriteUInt16BigEndian(maxPoints); + writer.WriteUInt16BigEndian(maxContours); + writer.WriteUInt16BigEndian(maxCompositePoints); + writer.WriteUInt16BigEndian(maxCompositeContours); + writer.WriteUInt16BigEndian(maxZones); + writer.WriteUInt16BigEndian(maxTwilightPoints); + writer.WriteUInt16BigEndian(maxStorage); + writer.WriteUInt16BigEndian(maxFunctionDefs); + writer.WriteUInt16BigEndian(maxInstructionDefs); + writer.WriteUInt16BigEndian(maxStackElements); + writer.WriteUInt16BigEndian(maxSizeOfInstructions); + writer.WriteUInt16BigEndian(maxComponentElements); + writer.WriteUInt16BigEndian(maxComponentDepth); + } + } + + public MaxpTable Clone() + { + return new MaxpTable + { + version = new Version16Dot16(this.version.RawValue), // Skapa ny instans + numGlyphs = this.numGlyphs, + maxPoints = this.maxPoints, + maxContours = this.maxContours, + maxCompositePoints = this.maxCompositePoints, + maxCompositeContours = this.maxCompositeContours, + maxZones = this.maxZones, + maxTwilightPoints = this.maxTwilightPoints, + maxStorage = this.maxStorage, + maxFunctionDefs = this.maxFunctionDefs, + maxInstructionDefs = this.maxInstructionDefs, + maxStackElements = this.maxStackElements, + maxSizeOfInstructions = this.maxSizeOfInstructions, + maxComponentElements = this.maxComponentElements, + maxComponentDepth = this.maxComponentDepth + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableConstants.cs b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableConstants.cs new file mode 100644 index 0000000000..a3595d44c5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableConstants.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Maxp +{ + internal class MaxpTableConstants + { + // Expected versions (raw 16.16 fixed values) + public const uint Version05 = 0x00005000; // 0.5 + public const uint Version10 = 0x00010000; // 1.0 + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableLoader.cs new file mode 100644 index 0000000000..a9de0c44fb --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableLoader.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Maxp +{ + internal class MaxpTableLoader : TableLoader + { + public MaxpTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Maxp) + { + } + + protected override MaxpTable LoadInternal() + { + var pos = _reader.BaseStream.Position; + var versionRawValue = _reader.ReadInt32BigEndian(); + var pos2 = _reader.BaseStream.Position; + var nGlyphs = _reader.ReadUInt16BigEndian(); + var maxp = new MaxpTable + { + version = new Version16Dot16(versionRawValue), + numGlyphs = nGlyphs + }; + if(maxp.version.Major == 1) + { + maxp.maxPoints = _reader.ReadUInt16BigEndian(); + maxp.maxContours = _reader.ReadUInt16BigEndian(); + maxp.maxCompositePoints = _reader.ReadUInt16BigEndian(); + maxp.maxCompositeContours = _reader.ReadUInt16BigEndian(); + maxp.maxZones = _reader.ReadUInt16BigEndian(); + maxp.maxTwilightPoints = _reader.ReadUInt16BigEndian(); + maxp.maxStorage = _reader.ReadUInt16BigEndian(); + maxp.maxFunctionDefs = _reader.ReadUInt16BigEndian(); + maxp.maxInstructionDefs = _reader.ReadUInt16BigEndian(); + maxp.maxStackElements = _reader.ReadUInt16BigEndian(); + maxp.maxSizeOfInstructions = _reader.ReadUInt16BigEndian(); + maxp.maxComponentElements = _reader.ReadUInt16BigEndian(); + maxp.maxComponentDepth = _reader.ReadUInt16BigEndian(); + } + return maxp; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableValidator.cs new file mode 100644 index 0000000000..aa00844aea --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Maxp/MaxpTableValidator.cs @@ -0,0 +1,114 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils; +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Maxp +{ + internal class MaxpTableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Maxp; } + } + + public override Type TableType => typeof(MaxpTable); + + + + public override TableValidationResult Validate(MaxpTable table, FontValidationContext context) + { + var result = new TableValidationResult(); + result.TableName = TableName; + result.LogLevel = base.LogLevel; + + // Rule 1: numGlyphs must be > 0 + if (table.numGlyphs <= 0) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("numGlyphs is {0}. Must be greater than 0.", table.numGlyphs)); + } + + // Rule 2: version must be 0x00005000 (0.5) or 0x00010000 (1.0) + if (table.version.RawValue != MaxpTableConstants.Version05 && table.version.RawValue != MaxpTableConstants.Version10) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("Unexpected version: 0x{0:X}. Expected {1:X} or {2:X}.", table.version.RawValue, MaxpTableConstants.Version05, MaxpTableConstants.Version10)); + } + + // Rule 3: Version-specific checks + if (table.version.RawValue == MaxpTableConstants.Version10) + { + // maxZones should be 1 or 2 (per spec text, most fonts use 2). + if (table.maxZones != 1 && table.maxZones != 2) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("maxZones is {0}. Expected 1 or 2.", table.maxZones)); + } + + // (Optional sanity) Ensure extended fields are not obviously inconsistent. + // Note: We do NOT enforce composite >= non-composite; that is not a spec requirement. + // All fields are ushort, so they are non-negative by type. + + // If you want a soft check on extremes, you could add informational notes + // for extremely large values, but avoid strict comparisons or false positives. + } + else if (table.version.RawValue == MaxpTableConstants.Version05) + { + // Version 0.5 only defines numGlyphs; extended fields should be zero. + if (table.maxPoints != 0 || table.maxContours != 0 || + table.maxCompositePoints != 0 || table.maxCompositeContours != 0 || + table.maxZones != 0 || table.maxTwilightPoints != 0 || + table.maxStorage != 0 || table.maxFunctionDefs != 0 || + table.maxInstructionDefs != 0 || table.maxStackElements != 0 || + table.maxSizeOfInstructions != 0 || table.maxComponentElements != 0 || + table.maxComponentDepth != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "Version 0.5 should not define extended fields (they should be zero)."); + } + } + + + // Rule 4: cross-table critical: numGlyphs matches loca + // Note: Loca must exist for essential fonts. If it is null, FontValidator should already report that. + if (context != null && context.Font != null && context.Font.LocaTable != null) + { + int locaGlyphCount = context.Font.LocaTable.GetGlyphCountSafe(); + // Implement GetGlyphCountSafe() in LocaTable to handle format properly. + + if (locaGlyphCount != table.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("numGlyphs ({0}) does not match loca glyph count ({1}).", table.numGlyphs, locaGlyphCount)); + } + } + + + return result; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecord.cs b/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecord.cs new file mode 100644 index 0000000000..a28b02052a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecord.cs @@ -0,0 +1,111 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontLocalization; +using System.Diagnostics; + +namespace EPPlus.Fonts.OpenType.Tables.Name +{ + [DebuggerDisplay("{RecordType}: {Name}")] + public class NameRecord : FontTableElement + { + /// + /// Platform identifier code. + /// + public ushort platformId { get; set; } + + /// + /// Platform-specific encoding identifier. + /// + public ushort encodingId { get; set; } + + /// + /// Language identifier. + /// + public ushort languageID { get; set; } + + /// + /// Name identifier. + /// + public ushort nameId { get; set; } + + public NameRecordTypes RecordType { get; set; } + + /// + /// Name string length in bytes. + /// + public ushort length { get; set; } + + /// + /// Name string offset in bytes from stringOffset. + /// + public ushort offset { get; set; } + + + public string Name { get; set; } + + public LanguageMapping LanguageMapping { get; set; } + + public override string ToString() + { + if(!IsNullOrWhiteSpace(Name)) + { + return Name; + } + else + { + return base.ToString(); + } + } + + internal static bool IsNullOrWhiteSpace(string value) + { + return value == null || value.Trim().Length == 0; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteUInt16BigEndian(platformId); + writer.WriteUInt16BigEndian(encodingId); + writer.WriteUInt16BigEndian(languageID); + writer.WriteUInt16BigEndian(nameId); + writer.WriteUInt16BigEndian(length); + writer.WriteUInt16BigEndian(offset); + + } + + + /// + /// Deep clone of NameRecord. + /// Note: 'length' and 'offset' are recomputed in NameTable.SerializeInternal. + /// + public NameRecord Clone() + { + return new NameRecord + { + platformId = this.platformId, + encodingId = this.encodingId, + languageID = this.languageID, + nameId = this.nameId, + RecordType = this.RecordType, + + // Do NOT trust old length/offset: they will be recalculated during serialization + length = this.length, + offset = this.offset, + + Name = this.Name, // string is immutable; safe to copy + LanguageMapping = this.LanguageMapping // assuming mapping is immutable/value-type-like; clone if needed + }; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecordTypes.cs b/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecordTypes.cs new file mode 100644 index 0000000000..fe0da67148 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Name/NameRecordTypes.cs @@ -0,0 +1,125 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Name +{ + /// + /// The following name IDs are pre-defined, and they apply to all platforms unless indicated otherwise. + /// Name IDs 26 to 255, inclusive, are reserved for future standard names. Name IDs 256 to 32767, inclusive, + /// are reserved for font-specific names such as those referenced by a font’s layout features. + /// https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids + /// + public enum NameRecordTypes : ushort + { + /// + /// The copyright string from the font vendor + /// + CopyrightNotice = 0, + /// + /// The name the user sees. Times New Roman + /// + FontFamilyName = 1, + /// + /// The name of the style. Bold + /// + FontSubfamilyName = 2, + /// + /// A unique identifier that applications can store to identify the font being used. Monotype: Times New Roman Bold:1990 + /// + UniqueFontIdentifier = 3, + /// + /// The complete, unique, human readable name of the font. This name is used by Windows. Times New Roman Bold + /// + FullFontName = 4, + /// + /// Release and version information from the font vendor. Version 1.00 June 1, 1990, initial release + /// + VersionString = 5, + /// + /// The name the font will be known by on a PostScript printer. TimesNewRoman-Bold + /// + PostScriptName = 6, + /// + /// Trademark string. Times New Roman is a registered trademark of the Monotype Corporation. + /// + TradeMark = 7, + /// + /// Manufacturer. Monotype Corporation plc + /// + ManufacturerName = 8, + /// + /// Designer. Stanley Morison + /// + Designer = 9, + /// + /// Description. Designed in 1932 for the Times of London newspaper. Excellent readability and a narrow overall width, allowing more words per line than most fonts. + /// + Description = 10, + /// + /// URL of Vendor. http://www.monotype.com + /// + UrlVendor = 11, + /// + /// URL of Designer. http://www.monotype.com + /// + UrlDesigner = 12, + /// + /// License Description. This font may be installed on all of your machines and printers, but you may not sell or give these fonts to anyone else. + /// + LicenseDescription = 13, + /// + /// License Info URL. http://www.monotype.com/license/ + /// + LicenseInfoUrl = 14, + Reserved1 = 15, + /// + /// Preferred Family. No name string present, since it is the same as name ID 1 (Font Family name). + /// + TypographicFamilyName = 16, + /// + /// Preferred Subfamily. No name string present, since it is the same as name ID 2 (Font Subfamily name). + /// + TypographicSubfamilyName = 17, + /// + /// Compatible Full (Macintosh only). No name string present, since it is the same as name ID 4 (Full name). + /// + CompatibleFull = 18, + /// + /// Sample text. The quick brown fox jumps over the lazy dog. + /// + SampleText = 19, + /// + /// PostScript CID findfont name. No name string present. Thus, the PostScript Name defined by name ID 6 should be used with the “findfont” invocation for locating the font in the context of a PostScript interpreter. + /// + PostScriptCID = 20, + /// + /// WWS family name: Since Times New Roman is a WWS font, this field does not need to be specified. If the font contained styles such as “caption”, “display”, “handwriting”, etc, that would be noted here. + /// + WWSfamilyName = 21, + /// + /// WWS subfamily name: Since Times New Roman is a WWS font, this field does not need to be specified. + /// + WWSsubfamilyName = 22, + /// + /// Light background palette name. No name string present, since this is not a color font. + /// + LightBackgroundPalette = 23, + /// + /// Dark background palette name. No name string present, since this is not a color font. + /// + DarkBackgroundPallet = 24, + /// + /// Variations PostScript name prefix. No name string present, since this is not a variable font. + /// + VariationsPostScriptName = 25 + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Name/NameTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTable.cs new file mode 100644 index 0000000000..f29a296ebf --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTable.cs @@ -0,0 +1,532 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontLocalization; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Name +{ + public class NameTable : FontTableBase + { + public override string Name => TableNames.Name; + + public override bool IsEssentialTable => false; + public ushort format { get; set; } + + public ushort count { get; set; } + + public ushort stringOffset { get; set; } + + public NameRecord[] NameRecords { get; set; } + + internal override void Clear() + { + throw new System.NotImplementedException(); + } + + public ushort Os2FsSelection { get; internal set; } + + + /// + /// Deep clone of NameTable. + /// Header fields (format, count, stringOffset) will be recomputed during serialization. + /// + public NameTable Clone() + { + var clone = new NameTable + { + // Keep the current format; will typically be 0 and recomputed anyway. + format = this.format, + + // 'count' and 'stringOffset' are recomputed in SerializeInternal + count = this.count, + stringOffset = this.stringOffset, + + NameRecords = CloneRecords(this.NameRecords) + }; + return clone; + } + + private static NameRecord[] CloneRecords(NameRecord[] source) + { + if (source == null || source.Length == 0) + return new NameRecord[0]; + + var copy = new NameRecord[source.Length]; + for (int i = 0; i < source.Length; i++) + copy[i] = source[i]?.Clone(); + return copy; + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + // Step 1: Write header + format = 0; + count = (ushort)(NameRecords?.Length ?? 0); + stringOffset = (ushort)(6 + count * 12); // 6 bytes header + 12 bytes per record + + writer.WriteUInt16BigEndian(format); + writer.WriteUInt16BigEndian(count); + writer.WriteUInt16BigEndian(stringOffset); + + // Step 2: Prepare string data with ENCODING-AWARE deduplication + var stringData = new List(); + // FIX: Include encoding in the key to avoid collisions between different encodings + var stringOffsetMap = new Dictionary(); + + foreach (var record in NameRecords) + { + var encoding = GetEncodingForRecord(record); + var str = record.Name ?? string.Empty; + var encoded = encoding.GetBytes(str); + + // FIX: Create a unique key that includes both the text AND the encoding + // This ensures that "Aptos Narrow" in ISO-8859-1 and UTF-16BE get different offsets + string dedupKey = $"{str}|{encoding.CodePage}"; + + if (!stringOffsetMap.TryGetValue(dedupKey, out var offset)) + { + offset = (ushort)stringData.Count; + stringOffsetMap[dedupKey] = offset; + stringData.AddRange(encoded); + } + + record.length = (ushort)encoded.Length; + record.offset = offset; + } + + // Step 3: Write NameRecords + foreach (var record in NameRecords) + { + record.Serialize(writer); + } + + // Step 4: Write string pool + writer.Write(stringData.ToArray()); + } + + // ALSO UPDATE GetEncodingForRecord() TO RESPECT encodingId: + private static Encoding GetEncodingForRecord(NameRecord record) + { + // Unicode platform + if (record.platformId == 0) + { + return Encoding.BigEndianUnicode; // UTF-16BE + } + + // Macintosh platform + if (record.platformId == 1) + { + // encodingId 0 = MacRoman (single-byte) + // .NET doesn't have MacRoman (codepage 10000) in all versions + // Fallback to ISO-8859-1 (Latin-1) + try + { + return Encoding.GetEncoding("ISO-8859-1"); + } + catch + { + return Encoding.UTF8; + } + } + + // Windows platform - CRITICAL: Must respect encodingId! + if (record.platformId == 3) + { + return GetWindowsEncoding(record.encodingId); + } + + // Fallback for unknown platforms + return Encoding.UTF8; + } + private static readonly Dictionary _fallbackEncodings = new Dictionary(); + // ADD GetWindowsEncoding() method: + private static Encoding GetWindowsEncoding(ushort encodingId) + { + try + { + if(_fallbackEncodings.TryGetValue(encodingId, out var cached)) + { + return cached; + } + switch (encodingId) + { + case 0: + // Symbol encoding – fallback to Windows-1252 + return Encoding.GetEncoding(1252); + + case 1: + // Unicode BMP (UCS-2) – UTF-16BE + // THIS IS THE MOST COMMON for modern fonts! + return Encoding.BigEndianUnicode; + + case 2: + // Shift-JIS – Japanese + return Encoding.GetEncoding(932); + + case 3: + // GB2312 – Simplified Chinese + return Encoding.GetEncoding(936); + + case 4: + // Big5 – Traditional Chinese + return Encoding.GetEncoding(950); + + case 5: + // Wansung – Korean + return Encoding.GetEncoding(949); + + case 6: + // Johab – Korean (alternative) + return Encoding.GetEncoding(1361); + + case 10: + // Unicode full repertoire + // .NET doesn't have UTF-32BE directly, use UTF-16BE + return Encoding.BigEndianUnicode; + + default: + // Fallback for unknown encodings + return Encoding.BigEndianUnicode; + } + } + catch (NotSupportedException) + { + // If encoding doesn't exist (e.g. in .NET Standard without System.Text.Encoding.CodePages) + // Fallback to UTF-16BE - this is safe for most modern fonts + lock (_fallbackEncodings) + { + _fallbackEncodings.Add(encodingId, Encoding.BigEndianUnicode); + } + + return Encoding.BigEndianUnicode; + } + catch (ArgumentException) + { + return Encoding.BigEndianUnicode; + } + } + + //private Encoding GetEncodingForRecord(NameRecord record) + //{ + // if (record.platformId == 0) + // return Encoding.GetEncoding("utf-16BE"); + + // if (record.platformId == 1) + // return Encoding.GetEncoding(10000); // MacRoman + + // if (record.platformId == 3) + // return NameTableLoader.GetWindowsEncoding(record.encodingId); + + // return Encoding.UTF8; // Fallback + //} + + /// + /// Loads the name table from raw table bytes (used during font scanning). + /// Only populates NameRecords – header fields are ignored as they will be rebuilt on write. + /// + /// Complete content of the 'name' table + /// + /// Loads the name table from raw table bytes (used during font scanning). + /// Populates NameRecords with decoded strings. Header fields are preserved for compatibility. + /// + /// Complete content of the 'name' table + /// + /// Loads the name table from raw table bytes (used during font scanning). + /// Populates NameRecords with decoded strings. Header fields are preserved for compatibility. + /// + /// Complete content of the 'name' table + public void LoadFromBytes(byte[] tableBytes) + { + if (tableBytes == null || tableBytes.Length < 6) + throw new ArgumentException("Invalid name table data"); + + using (var ms = new MemoryStream(tableBytes)) + using (var reader = new FontsBinaryReader(ms)) + { + format = reader.ReadUInt16BigEndian(); + count = reader.ReadUInt16BigEndian(); + stringOffset = reader.ReadUInt16BigEndian(); + + NameRecords = new NameRecord[count]; + + // Step 1: Read all name record headers + for (int i = 0; i < count; i++) + { + var record = new NameRecord + { + platformId = reader.ReadUInt16BigEndian(), + encodingId = reader.ReadUInt16BigEndian(), + languageID = reader.ReadUInt16BigEndian(), + nameId = reader.ReadUInt16BigEndian(), + length = reader.ReadUInt16BigEndian(), + offset = reader.ReadUInt16BigEndian() + }; + + record.RecordType = (NameRecordTypes)record.nameId; + + NameRecords[i] = record; + } + + // Step 2: Read all strings from string pool + for (int i = 0; i < count; i++) + { + var record = NameRecords[i]; + + if (record.length == 0) + { + record.Name = string.Empty; + continue; + } + + long stringPos = stringOffset + record.offset; + if (stringPos + record.length > tableBytes.Length) + continue; // corrupted + + ms.Position = stringPos; + byte[] stringBytes = reader.ReadBytes(record.length); + + Encoding encoding = GetEncodingForRecord(record); + record.Name = encoding.GetString(stringBytes); + + // Vi skippar LanguageMapping helt under scanning + // Det är bara tungt och behövs inte för att få Family/Subfamily + record.LanguageMapping = null; + } + } + } + + /// + /// Returns the preferred Full Font Name (name ID 4) with proper language fallback. + /// First tries platform-specific record without language (common default), + /// then falls back to explicit English (US). + /// + public string GetFullFontName() + { + // 1. Platform-specific record with no language tag (most common default) + string name = GetFirstNonEmpty(NameRecordTypes.FullFontName); + if (!string.IsNullOrEmpty(name)) + return name; + + // 2. Explicit English (US) – fallback + return GetEnglishName(NameRecordTypes.FullFontName); + } + + /// + /// Returns the preferred font family name using OpenType specification priority. + /// Prefers Typographic Family (16) over regular Family (1). + /// + public string GetFamilyName() + { + //// Typographic Family (16) first + //string name = GetFirstNonEmpty(NameRecordTypes.TypographicFamilyName); + //if (!string.IsNullOrEmpty(name)) + // return name; + + // Then regular Family Name (1) + string name = GetFirstNonEmpty(NameRecordTypes.FontFamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + // Typographic Family (16) first + name = GetFirstNonEmpty(NameRecordTypes.TypographicFamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + + // Fallback to English + name = GetEnglishName(NameRecordTypes.TypographicFamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + return GetEnglishName(NameRecordTypes.FontFamilyName) ?? "Unknown Family"; + } + + /// + /// Returns the preferred subfamily name. + /// Prefers Typographic Subfamily (17) over regular Subfamily (2). + /// + public string GetSubfamilyName() + { + string name = GetFirstNonEmpty(NameRecordTypes.TypographicSubfamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + name = GetFirstNonEmpty(NameRecordTypes.FontSubfamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + name = GetEnglishName(NameRecordTypes.TypographicSubfamilyName); + if (!string.IsNullOrEmpty(name)) + return name; + + return GetEnglishName(NameRecordTypes.FontSubfamilyName) ?? "Regular"; + } + + public FontSubFamily GetSubfamilyEnum() + { + string subfamily = GetSubfamilyName(); + + if (string.IsNullOrEmpty(subfamily)) + goto UseFsSelection; + + string lower = subfamily.ToLowerInvariant(); + + // Exakta matchningar först + if (lower == "regular" || lower == "normal" || lower == "roman" || lower == "book") + return FontSubFamily.Regular; + + if (lower == "bold") + return FontSubFamily.Bold; + + if (lower == "italic" || lower == "oblique") + return FontSubFamily.Italic; + + if (lower.Contains("bold") && lower.Contains("italic")) + return FontSubFamily.BoldItalic; + if (lower.Contains("bold") || lower.Contains("heavy") || lower.Contains("black") || lower.Contains("demi")) + return FontSubFamily.Bold; + if (lower.Contains("italic") || lower.Contains("oblique")) + return FontSubFamily.Italic; + + // Om name-tabellen är konstig → fallback till OS/2 + UseFsSelection: + return GetSubfamilyFromFsSelection(); + } + + private FontSubFamily GetSubfamilyFromFsSelection() + { + // Dessa bitar är definierade i OpenType-specen + const ushort ITALIC = 0x0001; + const ushort BOLD = 0x0020; + // OBS: Bit 6 (0x0040) är UNDERSCORED, bit 9 (0x0200) är REGULAR (används ibland) + + bool isItalic = (Os2FsSelection & ITALIC) != 0; + bool isBold = (Os2FsSelection & BOLD) != 0; + + if (isBold && isItalic) return FontSubFamily.BoldItalic; + if (isBold) return FontSubFamily.Bold; + if (isItalic) return FontSubFamily.Italic; + return FontSubFamily.Regular; + } + + private string GetFirstNonEmpty(NameRecordTypes type) + { + foreach (var r in NameRecords) + { + if (r.RecordType == type && !string.IsNullOrEmpty(r.Name)) + { + return r.Name; + } + } + return null; + } + + private string GetEnglishName(NameRecordTypes type) + { + foreach (var record in NameRecords) + { + if (record.RecordType == type && + record.LanguageMapping != null && + record.LanguageMapping.Language == Languages.English && + !string.IsNullOrEmpty(record.Name)) + { + return record.Name; + } + } + return null; + } + + /// + /// Returns the PostScript Name (nameID 6). + /// Follows OpenType recommendations: + /// 1. Prefer platform 3 (Windows) → UTF-16BE + /// 2. Then platform 1 (Macintosh) → MacRoman + /// 3. Then platform 0 (Unicode) + /// If no PostScript name exists, fallback to a sanitized FullFontName. + /// + public string PostScriptName + { + get + { + // 1. Windows (platform 3) – most reliable + var win = NameRecords + .Where(r => r.RecordType == NameRecordTypes.PostScriptName && r.platformId == 3) + .Select(r => r.Name) + .FirstOrDefault(n => !string.IsNullOrEmpty(n)); + if (!string.IsNullOrEmpty(win)) + return SanitizePsName(win); + + // 2. Unicode (platform 0) + var uni = NameRecords + .Where(r => r.RecordType == NameRecordTypes.PostScriptName && r.platformId == 0) + .Select(r => r.Name) + .FirstOrDefault(n => !string.IsNullOrEmpty(n)); + if (!string.IsNullOrEmpty(uni)) + return SanitizePsName(uni); + + // 3. Macintosh (platform 1) + var mac = NameRecords + .Where(r => r.RecordType == NameRecordTypes.PostScriptName && r.platformId == 1) + .Select(r => r.Name) + .FirstOrDefault(n => !string.IsNullOrEmpty(n)); + if (!string.IsNullOrEmpty(mac)) + return SanitizePsName(mac); + + // 4. If nameID 6 is missing – fallback to FullFontName (Windows) + var full = GetFullFontName(); + if (!string.IsNullOrEmpty(full)) + return SanitizePsName(full); + + // 5. Last fallback + return "UnknownPSName"; + } + } + /// + /// Sanitizes a name so it always becomes a valid PostScript-compatible font name. + /// Removes illegal characters and replaces whitespace with hyphens. + /// + private static string SanitizePsName(string name) + { + if (string.IsNullOrEmpty(name)) + return "UnknownPSName"; + + var sb = new StringBuilder(name.Length); + + foreach (char c in name) + { + if (char.IsWhiteSpace(c)) + { + sb.Append('-'); + continue; + } + + // Valid ASCII range for PostScript names + if (c >= 33 && c <= 126) + { + sb.Append(c); + continue; + } + + // Skip invalid characters + } + + // If everything got stripped + return sb.Length > 0 ? sb.ToString() : "UnknownPSName"; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableLoader.cs new file mode 100644 index 0000000000..e1b3d293ff --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableLoader.cs @@ -0,0 +1,157 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontLocalization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Name +{ + internal class NameTableLoader : TableLoader + { + public NameTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Name) + { +#if NET5_0_OR_GREATER + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); //Add Support for codepage 1252 +#endif + } + + protected override NameTable LoadInternal() + { + ushort format = _reader.ReadUInt16BigEndian(); + ushort count = _reader.ReadUInt16BigEndian(); + ushort stringOffset = _reader.ReadUInt16BigEndian(); + var globalStringOffset = _offset + stringOffset; + var records = new List(); + for(var x = 0; x < count; x++) + { + var platformId = _reader.ReadUInt16BigEndian(); + var encodingID = _reader.ReadUInt16BigEndian(); + var languageID = _reader.ReadUInt16BigEndian(); + var nameID = _reader.ReadUInt16BigEndian(); + var length = _reader.ReadUInt16BigEndian(); + var offset = _reader.ReadUInt16BigEndian(); + var record = new NameRecord + { + platformId = platformId, + encodingId = encodingID, + languageID = languageID, + nameId = nameID, + RecordType = (NameRecordTypes)nameID, + length = length, + offset = offset + }; + records.Add(record); + } + + foreach (var record in records) + { + _reader.BaseStream.Position = globalStringOffset + record.offset; + var bytes = _reader.ReadBytes(record.length); + SetName(record, bytes); + } + + return new NameTable + { + format = format, + count = count, + stringOffset = stringOffset, + NameRecords = records.ToArray() + }; + } + + private void SetName(NameRecord record, byte[] bytes) + { + // Macintosh platform + if (record.platformId == 1) + { + if (!Encoding.GetEncodings().Any(x => x.CodePage == 10000)) return; + var enc = Encoding.GetEncoding(10000); + record.Name = enc.GetString(bytes); + if(MacintoshLanguageMappings.Mappings.ContainsKey(record.languageID)) + { + record.LanguageMapping = MacintoshLanguageMappings.Mappings[record.languageID]; + } + } + // Unicode platform + else if (record.platformId == 0) + { + record.Name = Encoding.GetEncoding("utf-16BE").GetString(bytes); + } + // Windows platform + else if (record.platformId == 3) + { + if (WindowsLanguageMappings.Mappings.ContainsKey((int)record.languageID)) + { + record.LanguageMapping = WindowsLanguageMappings.Mappings[record.languageID]; + } + var enc = GetWindowsEncoding(record.encodingId); + record.Name = enc.GetString(bytes); + } + } + + internal static Encoding GetWindowsEncoding(int encodingId) + { + // Ensure CodePagesEncodingProvider is registered before calling this method: + // Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + try + { + switch (encodingId) + { + case 0: + // Symbol encoding – not Unicode. Fallback to Windows-1252 for compatibility. + return Encoding.GetEncoding(1252); + + case 1: + // Unicode BMP (UCS-2) – typically stored as UTF-16BE in font files. + return Encoding.GetEncoding("utf-16BE"); + + case 2: + // Shift-JIS – used for Japanese. + return Encoding.GetEncoding(932); + + case 3: + // PRC – Simplified Chinese (GB2312). + return Encoding.GetEncoding(936); + + case 4: + // Big5 – Traditional Chinese. + return Encoding.GetEncoding(950); + + case 5: + // Wansung – Korean. + return Encoding.GetEncoding(949); + + case 6: + // Johab – Korean (alternative encoding). + return Encoding.GetEncoding(1361); + + case 10: + // Unicode full repertoire – UTF-32BE. + return Encoding.GetEncoding("utf-32BE"); + + default: + // Fallback to UTF-16LE (default in .NET) for unknown or unsupported encodings. + return Encoding.Unicode; + } + } + catch (NotSupportedException) + { + // If the requested encoding is not available, fallback to UTF-16LE. + return Encoding.Unicode; + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableValidator.cs new file mode 100644 index 0000000000..5870236f39 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Name/NameTableValidator.cs @@ -0,0 +1,112 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Name +{ + internal class NameTableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Name; } + } + + public override Type TableType => typeof(NameTable); + + public override TableValidationResult Validate(NameTable table, FontValidationContext context) + { + TableValidationResult result = new TableValidationResult(); + result.TableName = TableName; + + // Rule 1: count vs NameRecords length + int actualCount = (table.NameRecords == null) ? 0 : table.NameRecords.Length; + if (table.count != actualCount) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("NameTable count ({0}) does not match NameRecords length ({1}).", table.count, actualCount)); + } + + // Rule 2: format check + if (table.format != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("NameTable format is {0}. Expected 0.", table.format)); + } + + if (table.NameRecords == null || table.NameRecords.Length == 0) + { + result.AddMessage(FontValidationSeverity.Error, "NameTable has no NameRecords."); + return result; + } + + // Find critical NameIDs + var postScriptNames = table.NameRecords.Where(r => r.nameId == 6).ToList(); + var familyNames = table.NameRecords.Where(r => r.nameId == 1).ToList(); + var subfamilyNames = table.NameRecords.Where(r => r.nameId == 2).ToList(); + + // Rule 3: PostScript Name must exist + if (postScriptNames.Count == 0) + { + result.AddMessage(FontValidationSeverity.Error, "PostScript Name (NameID 6) is missing."); + } + else + { + foreach (var psNameRecord in postScriptNames) + { + if (NameRecord.IsNullOrWhiteSpace(psNameRecord.Name)) + { + result.AddMessage(FontValidationSeverity.Error, "PostScript Name is empty or whitespace."); + } + else if (psNameRecord.Name.Contains(" ")) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("PostScript Name '{0}' contains spaces, which is not allowed.", psNameRecord.Name)); + } + + // Check platform for PostScript Name + if (psNameRecord.platformId != 3 && psNameRecord.platformId != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("PostScript Name '{0}' is not from Windows or Unicode platform (platformId={1}).", psNameRecord.Name, psNameRecord.platformId)); + } + } + } + + // Rule 4: Family and Subfamily should exist + if (familyNames.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "Font Family (NameID 1) is missing."); + } + if (subfamilyNames.Count == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "Font Subfamily (NameID 2) is missing."); + } + + // Optional: Check for empty names in critical records + foreach (var record in familyNames.Concat(subfamilyNames)) + { + if (NameRecord.IsNullOrWhiteSpace(record.Name)) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("NameID {0} is empty or whitespace.", record.nameId)); + } + } + + return result; + } + + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Table.cs b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Table.cs new file mode 100644 index 0000000000..f35b727110 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Table.cs @@ -0,0 +1,321 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +using System; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Utils; + +namespace EPPlus.Fonts.OpenType.Tables.Os2 +{ + public class Os2Table : FontTableBase + { + public override string Name => TableNames.Os2; + + public override bool IsEssentialTable => false; + /// + /// The version number for the OS/2 table: 0x0000 to 0x0005. + /// The version number allows for identification of the precise contents and layout for the OS/2 table. + /// + public ushort version { get; set; } + + /// + /// The Average Character Width parameter specifies the arithmetic average of the escapement (width) of all non-zero width glyphs in the font. + /// + public short xAvgCharWidth { get; set; } + + /// + /// Indicates the visual weight (degree of blackness or thickness of strokes) of the characters in the font. Values from 1 to 1000 are valid. + /// + public ushort usWeightClass { get; set; } + + /// + /// Indicates a relative change from the normal aspect ratio (width to height ratio) as specified by a font designer for the glyphs in a font. + /// + public ushort usWidthClass { get; set; } + + /// + /// Indicates font embedding licensing rights for the font. The interpretation of flags is as follows: + /// 0: Installable embedding: the font may be embedded, and may be permanently installed for use on a remote systems, or for use by other users. + /// 2: Restricted License embedding: the font must not be modified, embedded or exchanged in any manner without first obtaining explicit permission of the legal owner. + /// 4: Preview & Print embedding: the font may be embedded, and may be temporarily loaded on other systems for purposes of viewing or printing the document. Documents containing Preview & Print fonts must be opened “read-only”; no edits can be applied to the document. + /// 8: Editable embedding: the font may be embedded, and may be temporarily loaded on other systems. As with Preview & Print embedding, documents containing Editable fonts may be opened for reading. In addition, editing is permitted, including ability to format new text using the embedded font, and changes may be saved. + /// + public ushort fsType { get; set; } + + /// + /// The recommended horizontal size in font design units for subscripts for this font. + /// + public short ySubscriptXSize { get; set; } + + /// + /// The recommended vertical size in font design units for subscripts for this font. + /// + public short ySubscriptYSize { get; set; } + + /// + /// The recommended horizontal offset in font design units for subscripts for this font. + /// + public short ySubscriptXOffset { get; set; } + + /// + /// The recommended vertical offset in font design units from the baseline for subscripts for this font. + /// + public short ySubscriptYOffset { get; set; } + + /// + /// The recommended horizontal size in font design units for superscripts for this font. + /// + public short ySuperscriptXSize { get; set; } + + /// + /// The recommended vertical size in font design units for superscripts for this font. + /// + public short ySuperscriptYSize { get; set; } + + /// + /// The recommended horizontal offset in font design units for superscripts for this font. + /// + public short ySuperscriptXOffset { get; set; } + + /// + /// The recommended vertical offset in font design units from the baseline for superscripts for this font. + /// + public short ySuperscriptYOffset { get; set; } + + /// + /// Thickness of the strikeout stroke in font design units. + /// + public short yStrikeoutSize { get; set; } + + /// + /// The position of the top of the strikeout stroke relative to the baseline in font design units. + /// + public short yStrikeoutPosition { get; set; } + + /// + /// This parameter is a classification of font-family design. + /// The font class and font subclass are registered values assigned by IBM to each font family. This parameter is intended for use in selecting an alternate font when the requested font is not available. + /// + public short sFamilyClass { get; set; } + + /// + /// This 10-byte series of numbers is used to describe the visual characteristics of a given typeface. + /// See https://docs.microsoft.com/en-us/typography/opentype/spec/os2#panose + /// + public byte[] panose { get; set; } + + /// + /// This field is used to specify the Unicode blocks or ranges encompassed by the font file + /// in 'cmap' subtables for platform 3, encoding ID 1 (Microsoft platform, Unicode BMP) and + /// platform 3, encoding ID 10 (Microsoft platform, Unicode full repertoire) + /// See https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur + /// + public uint UnicodeRange1 { get; set; } + + public uint UnicodeRange2 { get; set; } + + public uint UnicodeRange3 { get; set; } + + public uint UnicodeRange4 { get; set; } + + /// + /// The four-character identifier for the vendor of the given type face. + /// + public Tag achVendId { get; set; } + + /// + /// Contains information concerning the nature of the font patterns + /// See https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fss + /// + public FsSelectionFlags fsSelection { get; set; } + [Flags] + public enum FsSelectionFlags : ushort + { + Italic = 1 << 0, // Bit 0 + Underscore = 1 << 1, // Bit 1 + Negative = 1 << 2, // Bit 2 + Outlined = 1 << 3, // Bit 3 + Strikeout = 1 << 4, // Bit 4 + Bold = 1 << 5, // Bit 5 + Regular = 1 << 6, // Bit 6 + UseTypoMetrics = 1 << 7, // Bit 7 + WWS = 1 << 8, // Bit 8 + Oblique = 1 << 9 // Bit 9 + // Bits 10-15 are reserved + } + //public FsSelectionFlags SelectionFlags => (FsSelectionFlags)fsSelection; + + + /// + /// The minimum Unicode index (character code) in this font, according to the 'cmap' subtable for + /// platform ID 3 and platform- specific encoding ID 0 or 1. For most fonts supporting Win-ANSI + /// or other character sets, this value would be 0x0020. This field cannot represent supplementary + /// character values (codepoints greater than 0xFFFF). Fonts that support supplementary characters + /// should set the value in this field to 0xFFFF if the minimum index value is a supplementary character. + /// + public ushort usFirstCharIndex { get; set; } + + /// + /// The maximum Unicode index (character code) in this font, according to the 'cmap' + /// subtable for platform ID 3 and encoding ID 0 or 1. This value depends on which character + /// sets the font supports. This field cannot represent supplementary character values (codepoints greater than 0xFFFF). + /// Fonts that support supplementary characters should set the value in this field to 0xFFFF. + /// + public ushort usLastCharIndex { get; set; } + + /// + /// The typographic ascender for this font. This field should be combined with the sTypoDescender and sTypoLineGap values to determine default line spacing. + /// See https://docs.microsoft.com/en-us/typography/opentype/spec/os2#stypoascender + /// + public short sTypoAscender { get; set; } + + /// + /// The typographic descender for this font. This field should be combined with the sTypoAscender and sTypoLineGap values to determine default line spacing. + /// https://docs.microsoft.com/en-us/typography/opentype/spec/os2#stypodescender + /// + public short sTypoDescender { get; set; } + + /// + /// The typographic line gap for this font. This field should be combined with the sTypoAscender and sTypoDescender values to determine default line spacing. + /// See https://docs.microsoft.com/en-us/typography/opentype/spec/os2#stypolinegap + /// + public short sTypoLineGap { get; set; } + + + public ushort usWinAscent { get; set; } + public ushort usWinDescent { get; set; } + public uint ulCodePageRange1 { get; set; } + public uint ulCodePageRange2 { get; set; } + public short sxHeight { get; set; } + public short sCapHeight { get; set; } + public ushort usDefaultChar { get; set; } + public ushort usBreakChar { get; set; } + public ushort usMaxContext { get; set; } + public ushort usLowerOpticalPointSize { get; set; } + public ushort usUpperOpticalPointSize { get; set; } + + public bool UseTypoMetrics => EnumUtil.HasFlag(fsSelection, FsSelectionFlags.UseTypoMetrics); + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + writer.WriteUInt16BigEndian(version); + writer.WriteInt16BigEndian(xAvgCharWidth); + writer.WriteUInt16BigEndian(usWeightClass); + writer.WriteUInt16BigEndian(usWidthClass); + writer.WriteUInt16BigEndian(fsType); + writer.WriteInt16BigEndian(ySubscriptXSize); + writer.WriteInt16BigEndian(ySubscriptYSize); + writer.WriteInt16BigEndian(ySubscriptXOffset); + writer.WriteInt16BigEndian(ySubscriptYOffset); + writer.WriteInt16BigEndian(ySuperscriptXSize); + writer.WriteInt16BigEndian(ySuperscriptYSize); + writer.WriteInt16BigEndian(ySuperscriptXOffset); + writer.WriteInt16BigEndian(ySuperscriptYOffset); + writer.WriteInt16BigEndian(yStrikeoutSize); + writer.WriteInt16BigEndian(yStrikeoutPosition); + writer.WriteInt16BigEndian(sFamilyClass); + writer.Write(panose); // 10 bytes + + writer.WriteUInt32BigEndian(UnicodeRange1); + writer.WriteUInt32BigEndian(UnicodeRange2); + writer.WriteUInt32BigEndian(UnicodeRange3); + writer.WriteUInt32BigEndian(UnicodeRange4); + + achVendId.Serialize(writer); // 4 bytes + + writer.WriteUInt16BigEndian((ushort)fsSelection); + writer.WriteUInt16BigEndian(usFirstCharIndex); + writer.WriteUInt16BigEndian(usLastCharIndex); + writer.WriteInt16BigEndian(sTypoAscender); + writer.WriteInt16BigEndian(sTypoDescender); + writer.WriteInt16BigEndian(sTypoLineGap); + writer.WriteUInt16BigEndian(usWinAscent); + writer.WriteUInt16BigEndian(usWinDescent); + + writer.WriteUInt32BigEndian(ulCodePageRange1); + writer.WriteUInt32BigEndian(ulCodePageRange2); + + writer.WriteInt16BigEndian(sxHeight); + writer.WriteInt16BigEndian(sCapHeight); + writer.WriteUInt16BigEndian(usDefaultChar); + writer.WriteUInt16BigEndian(usBreakChar); + writer.WriteUInt16BigEndian(usMaxContext); + if(version > 3) + { + writer.WriteUInt16BigEndian(usLowerOpticalPointSize); + writer.WriteUInt16BigEndian(usUpperOpticalPointSize); + } + } + + internal override void Clear() + { + throw new NotImplementedException(); + } + + /// + /// Creates a deep clone of the OS/2 table. + /// Used during font subsetting to ensure the new font has its own independent copy. + /// + /// A new Os2Table instance with identical values + public Os2Table Clone() + { + return new Os2Table + { + version = this.version, + xAvgCharWidth = this.xAvgCharWidth, + usWeightClass = this.usWeightClass, + usWidthClass = this.usWidthClass, + fsType = this.fsType, + ySubscriptXSize = this.ySubscriptXSize, + ySubscriptYSize = this.ySubscriptYSize, + ySubscriptXOffset = this.ySubscriptXOffset, + ySubscriptYOffset = this.ySubscriptYOffset, + ySuperscriptXSize = this.ySuperscriptXSize, + ySuperscriptYSize = this.ySuperscriptYSize, + ySuperscriptXOffset = this.ySuperscriptXOffset, + ySuperscriptYOffset = this.ySuperscriptYOffset, + yStrikeoutSize = this.yStrikeoutSize, + yStrikeoutPosition = this.yStrikeoutPosition, + sFamilyClass = this.sFamilyClass, + + // Deep clone of Panose (10-byte array) + panose = this.panose != null ? (byte[])this.panose.Clone() : null, + + UnicodeRange1 = this.UnicodeRange1, + UnicodeRange2 = this.UnicodeRange2, + UnicodeRange3 = this.UnicodeRange3, + UnicodeRange4 = this.UnicodeRange4, + + achVendId = this.achVendId, // Tag is immutable + + fsSelection = this.fsSelection, + usFirstCharIndex = this.usFirstCharIndex, + usLastCharIndex = this.usLastCharIndex, + sTypoAscender = this.sTypoAscender, + sTypoDescender = this.sTypoDescender, + sTypoLineGap = this.sTypoLineGap, + usWinAscent = this.usWinAscent, + usWinDescent = this.usWinDescent, + ulCodePageRange1 = this.ulCodePageRange1, + ulCodePageRange2 = this.ulCodePageRange2, + sxHeight = this.sxHeight, + sCapHeight = this.sCapHeight, + usDefaultChar = this.usDefaultChar, + usBreakChar = this.usBreakChar, + usMaxContext = this.usMaxContext, + usLowerOpticalPointSize = this.usLowerOpticalPointSize, + usUpperOpticalPointSize = this.usUpperOpticalPointSize + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2TableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2TableLoader.cs new file mode 100644 index 0000000000..ce51d90ebd --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2TableLoader.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Os2 +{ + internal class Os2TableLoader : TableLoader + { + public Os2TableLoader(TableLoaderSettings settings) : base(settings, TableNames.Os2) + { + } + + protected override Os2Table LoadInternal() + { + var version = _reader.ReadUInt16BigEndian(); + var xAvgCharWidth = _reader.ReadInt16BigEndian(); + var usWeightClass = _reader.ReadUInt16BigEndian(); + var usWidthClass = _reader.ReadUInt16BigEndian(); + var fsType = _reader.ReadUInt16BigEndian(); + var ySubscriptXSize = _reader.ReadInt16BigEndian(); + var ySubscriptYSize = _reader.ReadInt16BigEndian(); + var ySubscriptXOffset = _reader.ReadInt16BigEndian(); + var ySubscriptYOffset = _reader.ReadInt16BigEndian(); + var ySuperscriptXSize = _reader.ReadInt16BigEndian(); + var ySuperscriptYSize = _reader.ReadInt16BigEndian(); + var ySuperscriptXOffset = _reader.ReadInt16BigEndian(); + var ySuperscriptYOffset = _reader.ReadInt16BigEndian(); + var yStrikeoutSize = _reader.ReadInt16BigEndian(); + var yStrikeoutPosition = _reader.ReadInt16BigEndian(); + var familyClass = _reader.ReadInt16BigEndian(); + // read panose + var panose = new byte[10]; + for(var x = 0; x < 10; x++) + { + panose[x] = _reader.ReadByte(); + } + var ucr1 = _reader.ReadUInt32BigEndian(); + var ucr2 = _reader.ReadUInt32BigEndian(); + var ucr3 = _reader.ReadUInt32BigEndian(); + var ucr4 = _reader.ReadUInt32BigEndian(); + var achVendId = new Tag(_reader); + var fsSelection = _reader.ReadUInt16BigEndian(); + var usFirstCharIndex = _reader.ReadUInt16BigEndian(); + var usLastCharIndex = _reader.ReadUInt16BigEndian(); + var sTypoAscender = _reader.ReadInt16BigEndian(); + var sTypoDescender = _reader.ReadInt16BigEndian(); + var sTypoLineGap = _reader.ReadInt16BigEndian(); + + var usWinAscent = _reader.ReadUInt16BigEndian(); + var usWinDescent = _reader.ReadUInt16BigEndian(); + var ulCodePageRange1 = _reader.ReadUInt32BigEndian(); + var ulCodePageRange2 = _reader.ReadUInt32BigEndian(); + var sxHeight = _reader.ReadInt16BigEndian(); + var sCapHeight = _reader.ReadInt16BigEndian(); + var usDefaultChar = _reader.ReadUInt16BigEndian(); + var usBreakChar = _reader.ReadUInt16BigEndian(); + var usMaxContext = _reader.ReadUInt16BigEndian(); + ushort usLowerOpticalPointSize = default; + ushort usUpperOpticalPointSize = default; + if (version > 3) + { + usLowerOpticalPointSize = _reader.ReadUInt16BigEndian(); + usUpperOpticalPointSize = _reader.ReadUInt16BigEndian(); + } + + + + var table = new Os2Table + { + version = version, + xAvgCharWidth = xAvgCharWidth, + usWeightClass = usWeightClass, + usWidthClass = usWidthClass, + fsType = fsType, + ySubscriptXSize = ySubscriptXSize, + ySubscriptYSize = ySubscriptYSize, + ySubscriptXOffset = ySubscriptXOffset, + ySubscriptYOffset = ySubscriptYOffset, + ySuperscriptXSize = ySuperscriptXSize, + ySuperscriptYSize = ySuperscriptYSize, + ySuperscriptXOffset = ySuperscriptXOffset, + ySuperscriptYOffset = ySuperscriptYOffset, + yStrikeoutSize = yStrikeoutSize, + yStrikeoutPosition = yStrikeoutPosition, + sFamilyClass = familyClass, + panose = panose, + UnicodeRange1 = ucr1, + UnicodeRange2 = ucr2, + UnicodeRange3 = ucr3, + UnicodeRange4 = ucr4, + achVendId = achVendId, + fsSelection = (Os2Table.FsSelectionFlags)fsSelection, + usFirstCharIndex = usFirstCharIndex, + usLastCharIndex = usLastCharIndex, + sTypoAscender = sTypoAscender, + sTypoDescender = sTypoDescender, + sTypoLineGap = sTypoLineGap, + + usWinAscent = usWinAscent, + usWinDescent = usWinDescent, + ulCodePageRange1 = ulCodePageRange1, + ulCodePageRange2 = ulCodePageRange2, + sxHeight = sxHeight, + sCapHeight = sCapHeight, + usDefaultChar = usDefaultChar, + usBreakChar = usBreakChar, + usMaxContext = usMaxContext, + }; + if(table.version > 3) + { + table.usLowerOpticalPointSize = usLowerOpticalPointSize; + table.usUpperOpticalPointSize = usUpperOpticalPointSize; + } + return table; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Validator.cs b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Validator.cs new file mode 100644 index 0000000000..e75381d5d7 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Os2/Os2Validator.cs @@ -0,0 +1,180 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using EPPlus.Fonts.OpenType.FontValidation; + +namespace EPPlus.Fonts.OpenType.Tables.Os2 +{ + internal class Os2TableValidator : TableValidatorBase + { + public override string TableName + { + get { return TableNames.Os2; } + } + + public override Type TableType => typeof(Os2Table); + + + + public override TableValidationResult Validate(Os2Table table, FontValidationContext context) + { + var result = new TableValidationResult { TableName = TableName }; + + // ------------------------- + // Basic OS/2 checks + // ------------------------- + + // Version check + if (table.version < 0 || table.version > 5) + { + result.AddMessage(FontValidationSeverity.Warning, + $"Unexpected OS/2 version: {table.version}. Expected 0–5."); + } + + // usWeightClass (100–900) + if (table.usWeightClass < 100 || table.usWeightClass > 900) + { + result.AddMessage(FontValidationSeverity.Error, + $"usWeightClass out of range: {table.usWeightClass}. Expected 100–900."); + } + + // usWidthClass (1–9) + if (table.usWidthClass < 1 || table.usWidthClass > 9) + { + result.AddMessage(FontValidationSeverity.Error, + $"usWidthClass out of range: {table.usWidthClass}. Expected 1–9."); + } + + // fsType basic info + if ((table.fsType & 0x0002) != 0) + { + result.AddMessage(FontValidationSeverity.Information, + "Font has restricted embedding (fsType bit 1 set)."); + } + + // Subscript/Superscript sizes > 0 + if (table.ySubscriptXSize <= 0 || table.ySuperscriptXSize <= 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "Subscript/Superscript sizes should be greater than zero."); + } + + // Panose check (warn if all zeros) + if (table.panose != null && table.panose.Length == 10 && Array.TrueForAll(table.panose, b => b == 0)) + { + result.AddMessage(FontValidationSeverity.Warning, "Panose classification is all zeros."); + } + + // ------------------------- + // Cross-table: OS/2 vs cmap + // ------------------------- + if (context.Font.CmapTable != null) + { + int minChar = context.Font.CmapTable.GetMinCharCode(); + int maxChar = context.Font.CmapTable.GetMaxCharCode(); + if (minChar < table.usFirstCharIndex || maxChar > table.usLastCharIndex) + { + result.AddMessage(FontValidationSeverity.Error, + $"Cmap character range ({minChar}-{maxChar}) is outside OS/2 declared range ({table.usFirstCharIndex}-{table.usLastCharIndex})."); + } + + // Check default and break char exist in cmap + if (!context.Font.CmapTable.ContainsChar(table.usDefaultChar)) + { + result.AddMessage(FontValidationSeverity.Error, + $"usDefaultChar ({table.usDefaultChar}) not found in cmap."); + } + if (!context.Font.CmapTable.ContainsChar(table.usBreakChar)) + { + result.AddMessage(FontValidationSeverity.Error, + $"usBreakChar ({table.usBreakChar}) not found in cmap."); + } + } + + // ------------------------- + // Critical rules for subsetting + // ------------------------- + + // Embedding permissions + if ((table.fsType & 0x0002) != 0) + { + result.AddMessage(FontValidationSeverity.Error, + "Embedding is restricted (fsType bit 1 set). Subsetting cannot proceed."); + } + if ((table.fsType & 0x0008) != 0) + { + result.AddMessage(FontValidationSeverity.Error, + "No subsetting allowed (fsType bit 3 set)."); + } + if ((table.fsType & 0x0004) != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "Preview & Print embedding only (fsType bit 2 set). Check usage context."); + } + + // Metrics must be valid + if (table.sTypoAscender == 0 || table.sTypoDescender == 0) + { + result.AddMessage(FontValidationSeverity.Error, + "sTypoAscender and sTypoDescender must be non-zero for proper line spacing."); + } + if (table.usWinAscent == 0 || table.usWinDescent == 0) + { + result.AddMessage(FontValidationSeverity.Error, + "usWinAscent and usWinDescent must be non-zero for bounding box calculations."); + } + + // ------------------------- + // Cross-table: OS/2 vs head + // ------------------------- + if (context.Font.HeadTable != null) + { + if (table.usWinAscent < context.Font.HeadTable.Ymax || table.usWinDescent < Math.Abs(context.Font.HeadTable.Ymin)) + { + result.AddMessage(FontValidationSeverity.Warning, + "usWinAscent/usWinDescent do not cover font bounding box from head table. Consider updating after subsetting."); + } + } + + // ------------------------- + // Cross-table: OS/2 vs hhea + // ------------------------- + if (context.Font.HheaTable != null) + { + if (table.sTypoAscender != context.Font.HheaTable.ascender || + table.sTypoDescender != context.Font.HheaTable.descender) + { + result.AddMessage(FontValidationSeverity.Warning, + "OS/2 typographic metrics differ from hhea metrics. Consider harmonizing for consistency."); + } + } + + // ------------------------- + // Subset-specific range check + // ------------------------- + //if (context.SubsetChars != null && context.SubsetChars.Count > 0) + //{ + // int subsetMin = context.SubsetChars.Min; + // int subsetMax = context.SubsetChars.Max; + // if (subsetMin < table.usFirstCharIndex || subsetMax > table.usLastCharIndex) + // { + // result.AddMessage(FontValidationSeverity.Error, + // $"Subset character range ({subsetMin}-{subsetMax}) is outside OS/2 declared range ({table.usFirstCharIndex}-{table.usLastCharIndex}). Update required."); + // } + //} + + return result; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Post/PostTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTable.cs new file mode 100644 index 0000000000..d42d671061 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTable.cs @@ -0,0 +1,131 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Post +{ + public class PostTable : FontTableBase + { + public override string Name => TableNames.Post; + + public override bool IsEssentialTable => false; + public Version16Dot16 version { get; set; } + public Fixed16Dot16 italicAngle { get; set; } + public short underlinePosition { get; set; } + public short underlineThickness { get; set; } + public uint isFixedPitch { get; set; } + public uint minMemType42 { get; set; } + public uint maxMemType42 { get; set; } + public uint minMemType1 { get; set; } + public uint maxMemType1 { get;set; } + + // version 2 + + public ushort numGlyphs { get; set; } + + public List glyphNameIndex { get; set; } = new List(); + public List glyphNames { get; set; } = new List(); + + + + internal override void Clear() + { + underlinePosition = 0; + underlineThickness = 0; + isFixedPitch = 0; + minMemType42 = 0; + maxMemType42 = 0; + minMemType1 = 0; + maxMemType1 = 0; + + glyphNameIndex.Clear(); + glyphNames.Clear(); + } + + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + version.Serialize(writer); + italicAngle.Serialize(writer); + writer.WriteInt16BigEndian(underlinePosition); + writer.WriteInt16BigEndian(underlineThickness); + writer.WriteUInt32BigEndian(isFixedPitch); + writer.WriteUInt32BigEndian(minMemType42); + writer.WriteUInt32BigEndian(maxMemType42); + writer.WriteUInt32BigEndian(minMemType1); + writer.WriteUInt32BigEndian(maxMemType1); + if(version.Major == 2 && version.Minor == 0) + { + writer.WriteUInt16BigEndian(numGlyphs); + + // 1. Write glyphNameIndex[] + foreach (var index in glyphNameIndex) + { + writer.WriteUInt16BigEndian(index); + } + + // 2. Write Pascal strings for custom names (index >= 258) + for (int i = 0; i < glyphNameIndex.Count; i++) + { + ushort index = glyphNameIndex[i]; + if (index >= 258) + { + string name = glyphNames[i]; + byte[] nameBytes = System.Text.Encoding.ASCII.GetBytes(name); + if (nameBytes.Length > 255) + throw new InvalidOperationException($"Glyph name '{name}' is too long (max 255 bytes)."); + + writer.Write((byte)nameBytes.Length); // Pascal length + writer.Write(nameBytes); // ASCII name + } + } + } + } + + /// + /// Creates a deep clone of the post table. + /// Used during font subsetting to ensure the subset has an independent copy. + /// Handles both version 1.0 and 2.0 formats correctly. + /// + /// A new PostTable instance with identical data + public PostTable Clone() + { + var clone = new PostTable + { + version = this.version, + italicAngle = this.italicAngle, + underlinePosition = this.underlinePosition, + underlineThickness = this.underlineThickness, + isFixedPitch = this.isFixedPitch, + minMemType42 = this.minMemType42, + maxMemType42 = this.maxMemType42, + minMemType1 = this.minMemType1, + maxMemType1 = this.maxMemType1, + + numGlyphs = this.numGlyphs, + + // Deep clone lists – viktigt för version 2.0 + glyphNameIndex = this.glyphNameIndex != null + ? new List(this.glyphNameIndex) + : new List(), + + glyphNames = this.glyphNames != null + ? new List(this.glyphNames) + : new List() + }; + + return clone; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableConstants.cs b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableConstants.cs new file mode 100644 index 0000000000..ba705c93c0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableConstants.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Tables.Post +{ + internal class PostTableConstants + { + + // Allowed versions (raw 16.16 fixed values) + public const int Version10 = 0x00010000; // 1.0 + public const int Version20 = 0x00020000; // 2.0 + public const int Version25 = 0x00025000; // 2.5 + public const int Version30 = 0x00030000; // 3.0 + + // Standard Mac glyph name list count for format 2.0 baseline + public const int StandardMacGlyphNameCount = 258; + + // Reasonable italic angle bounds (soft checks) + public const int ItalicAngleMaxAbsDegreesWarning = 90; // warn if exceeds this + + // Underline thickness: should be > 0, optionally compare to UnitsPerEm + public const int MinUnderlineThickness = 1; + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableLoader.cs new file mode 100644 index 0000000000..dd05e4f4c6 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableLoader.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Post +{ + internal class PostTableLoader : TableLoader + { + public PostTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Post) + { + } + + protected override PostTable LoadInternal() + { + var versionRaw = _reader.ReadInt32BigEndian(); + var italicAngleRaw = _reader.ReadInt32BigEndian(); + var underlinePosition = _reader.ReadInt16BigEndian(); + var underlineThickness = _reader.ReadInt16BigEndian(); + var isFixedPitch = _reader.ReadUInt32BigEndian(); + var minMemType42 = _reader.ReadUInt32BigEndian(); + var maxMemType42 = _reader.ReadUInt32BigEndian(); + var minMemType1 = _reader.ReadUInt32BigEndian(); + var maxMemType1 = _reader.ReadUInt32BigEndian(); + + var post = new PostTable() + { + version = new Version16Dot16(versionRaw), + italicAngle = new Fixed16Dot16(italicAngleRaw), + underlinePosition = underlinePosition, + underlineThickness = underlineThickness, + isFixedPitch = isFixedPitch, + minMemType42 = minMemType42, + maxMemType42 = maxMemType42, + minMemType1 = minMemType1, + maxMemType1 = maxMemType1, + }; + if(post.version.Major == 2 && post.version.Minor == 0) + { + post.numGlyphs = _reader.ReadUInt16BigEndian(); + post.glyphNameIndex = new List(); + for(var i = 0; i < post.numGlyphs; i++) + { + post.glyphNameIndex.Add(_reader.ReadUInt16BigEndian()); + } + + // Read the Pascal-strings + var stringList = new List(); + while (_reader.BaseStream.Position < _offset + _length) + { + byte len = _reader.ReadByte(); + var strBytes = _reader.ReadBytes(len); + var str = System.Text.Encoding.ASCII.GetString(strBytes); + stringList.Add(str); + } + + post.glyphNames = stringList; + + } + return post; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableValidator.cs new file mode 100644 index 0000000000..f3aa5c7d6f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Post/PostTableValidator.cs @@ -0,0 +1,227 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; + + +namespace EPPlus.Fonts.OpenType.Tables.Post +{ + internal class PostTableValidator : TableValidatorBase + { + public override string TableName { get { return TableNames.Post; } } + public override Type TableType { get { return typeof(PostTable); } } + + public override TableValidationResult Validate(PostTable table, FontValidationContext context) + { + TableValidationResult result = new TableValidationResult(); + result.TableName = TableName; + + // ---------- Rule 1: Version check ---------- + + int rawVersion = table.version.RawValue; // int, not uint + bool isV10 = rawVersion == PostTableConstants.Version10; + bool isV20 = rawVersion == PostTableConstants.Version20; + bool isV25 = rawVersion == PostTableConstants.Version25; + bool isV30 = rawVersion == PostTableConstants.Version30; + + if (!isV10 && !isV20 && !isV25 && !isV30) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("Invalid post version: 0x{0:X}. Expected 0x00010000 (1.0), 0x00020000 (2.0), 0x00025000 (2.5) or 0x00030000 (3.0).", rawVersion)); + } + + + // ---------- Rule 2: isFixedPitch must be 0 or 1 ---------- + if (table.isFixedPitch != 0 && table.isFixedPitch != 1) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("isFixedPitch is {0}. Expected 0 (proportional) or 1 (monospaced).", table.isFixedPitch)); + } + + // ---------- Rule 3: Underline thickness ---------- + if (table.underlineThickness <= 0) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("underlineThickness ({0}) should be greater than 0.", table.underlineThickness)); + } + else + { + // Optional: compare to unitsPerEm (soft check) + if (context != null && context.Font != null && context.Font.HeadTable != null) + { + int unitsPerEm = context.Font.HeadTable.UnitsPerEm; + if (table.underlineThickness > unitsPerEm) + { + result.AddMessage(FontValidationSeverity.Information, + string.Format("underlineThickness ({0}) exceeds unitsPerEm ({1}).", table.underlineThickness, unitsPerEm)); + } + } + } + + // ---------- Rule 4: Italic angle sanity (soft) ---------- + // Fixed16Dot16 likely exposes double or float; assume .ToDouble() or similar. If not, adjust accordingly. + float italicAngleValue = table.italicAngle.FloatValue; + if (Math.Abs(italicAngleValue) > PostTableConstants.ItalicAngleMaxAbsDegreesWarning) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("italicAngle ({0}) is unusually large.", italicAngleValue)); + } + + // ---------- Rule 5: Version-specific checks ---------- + if (isV20) + { + // v2.0 has glyph names via glyphNameIndex and Pascal strings (for indices >= 258) + // Critical: numGlyphs must be > 0 and align with name arrays + if (table.numGlyphs <= 0) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: numGlyphs is {0}. Must be greater than 0.", table.numGlyphs)); + } + + // Arrays must be present and aligned (your serializer accesses glyphNames[i] for all i) + if (table.glyphNameIndex == null || table.glyphNameIndex.Count != table.numGlyphs) + { + int actual = (table.glyphNameIndex == null) ? 0 : table.glyphNameIndex.Count; + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: glyphNameIndex count ({0}) does not match numGlyphs ({1}).", actual, table.numGlyphs)); + } + + if (table.glyphNames == null || table.glyphNames.Count != table.numGlyphs) + { + int actual = (table.glyphNames == null) ? 0 : table.glyphNames.Count; + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: glyphNames count ({0}) does not match numGlyphs ({1}).", actual, table.numGlyphs)); + } + + // Cross-table critical: must match maxp.numGlyphs + if (context != null && context.Font != null && context.Font.MaxpTable != null) + { + if (context.Font.MaxpTable.numGlyphs != table.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: numGlyphs ({0}) does not match maxp.numGlyphs ({1}).", + table.numGlyphs, context.Font.MaxpTable.numGlyphs)); + } + } + + // Validate per-entry rules + if (table.glyphNameIndex != null && table.glyphNames != null && + table.glyphNameIndex.Count == table.glyphNames.Count) + { + // Count custom names (index >= 258) + int customCount = 0; + + for (int i = 0; i < table.glyphNameIndex.Count; i++) + { + ushort idx = table.glyphNameIndex[i]; + string name = table.glyphNames[i]; + + if (idx >= PostTableConstants.StandardMacGlyphNameCount) + { + customCount++; + + // Custom names must be ASCII and <= 255 bytes (Pascal length limit) + if (name == null) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: glyphNames[{0}] is null for custom index {1}.", i, idx)); + continue; + } + + byte[] asciiBytes = System.Text.Encoding.ASCII.GetBytes(name); + if (asciiBytes.Length > 255) + { + result.AddMessage(FontValidationSeverity.Error, + string.Format("post v2.0: glyphNames[{0}] ('{1}') exceeds 255 bytes.", i, name)); + } + + // Soft check: ensure all characters are 7-bit ASCII + for (int b = 0; b < asciiBytes.Length; b++) + { + if (asciiBytes[b] > 0x7F) + { + result.AddMessage(FontValidationSeverity.Warning, + string.Format("post v2.0: glyphNames[{0}] ('{1}') contains non-ASCII characters.", i, name)); + break; + } + } + } + else + { + // idx < 258 uses standard Mac glyph name list; custom string should not be serialized. + // Your serializer still reads glyphNames[i] but only writes for idx >= 258. + // If you want stricter hygiene, warn when a standard index has a non-empty custom name. + if (!string.IsNullOrEmpty(name)) + { + result.AddMessage(FontValidationSeverity.Information, + string.Format("post v2.0: glyphNames[{0}] is non-empty ('{1}') for standard index {2}. It will not be serialized.", i, name, idx)); + } + } + } + + // Optional sanity: the number of custom indices should match the count of non-empty custom names. + // Since you store a glyphNames entry for each glyph, we used presence of idx >= 258 as the authoritative rule. + } + } + else if (isV25) + { + // v2.5: glyph name indices replaced with offsets to standard Mac names; no custom Pascal strings. + // Given your data model does not expose specific 2.5 arrays, we at least warn if arrays are populated. + if ((table.glyphNameIndex != null && table.glyphNameIndex.Count > 0) || + (table.glyphNames != null && table.glyphNames.Count > 0) || + table.numGlyphs > 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "post v2.5: Custom glyph name arrays are not expected; data will be ignored."); + } + } + else if (isV30) + { + // v3.0: no glyph names are stored. Names are not provided; recommend arrays empty. + if ((table.glyphNameIndex != null && table.glyphNameIndex.Count > 0) || + (table.glyphNames != null && table.glyphNames.Count > 0) || + table.numGlyphs > 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "post v3.0: Glyph names should not be present; arrays should be empty."); + } + } + else if (isV10) + { + // v1.0: legacy; no glyph names arrays defined. Keep soft check similar to v3.0. + if ((table.glyphNameIndex != null && table.glyphNameIndex.Count > 0) || + (table.glyphNames != null && table.glyphNames.Count > 0) || + table.numGlyphs > 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "post v1.0: Glyph name arrays are not expected; arrays should be empty."); + } + } + + // ---------- Rule 6: Memory fields consistency ---------- + // In many modern fonts, these are zeroed—especially in v3.0. We keep this as a soft check. + if (isV30) + { + if (table.minMemType42 != 0 || table.maxMemType42 != 0 || + table.minMemType1 != 0 || table.maxMemType1 != 0) + { + result.AddMessage(FontValidationSeverity.Information, + "post v3.0: min/max memory fields are typically zero in modern fonts."); + } + } + + return result; + } + } +} + diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableCache.cs b/src/EPPlus.Fonts.OpenType/Tables/TableCache.cs new file mode 100644 index 0000000000..a6e8e89dce --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableCache.cs @@ -0,0 +1,118 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables +{ + using System.Threading; + + internal class TableCache + { + private readonly Dictionary _cachedTables = new Dictionary(); + private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + + public bool TryGet(string key, out object value) + { + _lock.EnterReadLock(); + try + { + return _cachedTables.TryGetValue(key, out value); + } + finally + { + _lock.ExitReadLock(); + } + } + + public object Get(string key) + { + _lock.EnterReadLock(); + try + { + return _cachedTables[key]; + } + finally + { + _lock.ExitReadLock(); + } + } + + public bool Contains(string key) + { + _lock.EnterReadLock(); + try + { + return _cachedTables.ContainsKey(key); + } + finally + { + _lock.ExitReadLock(); + } + } + + public void Add(string key, object val) + { + _lock.EnterWriteLock(); + try + { + _cachedTables.Add(key, val); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public void AddOrReplace(string key, object val) + { + _lock.EnterWriteLock(); + try + { + _cachedTables[key] = val; // Enklare än ContainsKey + Remove + } + finally + { + _lock.ExitWriteLock(); + } + } + + public void Clear() + { + _lock.EnterWriteLock(); + try + { + _cachedTables.Clear(); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public int Count + { + get + { + _lock.EnterReadLock(); + try + { + return _cachedTables.Count; + } + finally + { + _lock.ExitReadLock(); + } + } + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/TableLoader.cs new file mode 100644 index 0000000000..aa7588178f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableLoader.cs @@ -0,0 +1,119 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/07/2026 EPPlus Software AB Fixed threading with shared loaders + *************************************************************************************************/ +using System.Collections.Generic; +using System; +using System.Threading; + +namespace EPPlus.Fonts.OpenType.Tables +{ + internal abstract class TableLoader + where T : FontTableBase + { + public TableLoader(TableLoaderSettings tblSettings, string tableName) + { + _reader = tblSettings.TableReaderFactory.CreateReader(); + if (tblSettings._tableRecordsRef.ContainsKey(tableName)) + { + _offset = tblSettings._tableRecordsRef[tableName].Offset; + _length = tblSettings._tableRecordsRef[tableName].Length; + } + _tables = tblSettings._tableRecordsRef; + _tableName = tableName; + tableCache = tblSettings._tblCacheRef; + _fontLock = tblSettings._loaderCacheRef.SyncLock; // <-- Add this + } + + protected FontsBinaryReader _reader; + private readonly string _tableName; + protected readonly uint _offset; + protected readonly uint _length; + protected Dictionary _tables; + internal TableCache tableCache; + private readonly object _fontLock; // <-- Add this + + protected abstract T LoadInternal(); + + private readonly object _instanceLock = new object(); + private bool _isLoading; + private bool _isLoaded; + + public T Load(bool useCache = true) + { + // First: Check cache with instance lock (fast path) + lock (_instanceLock) + { + object cached; + if (_isLoaded && tableCache != null && tableCache.TryGet(_tableName, out cached) && useCache) + { + return cached as T; // ✅ Atomisk operation! + } + + while (_isLoading && !_isLoaded) + { + Monitor.Wait(_instanceLock); + } + + if (_isLoaded && tableCache != null && tableCache.TryGet(_tableName, out cached) && useCache) + { + return cached as T; // ✅ Atomisk operation! + } + + _isLoading = true; + } + + T t; + + // Second: Load table with font-level lock (protects ALL reader access for this font) + lock (_fontLock) + { + // ✅ FIX: Triple-check med TryGet + object cached; + if (tableCache != null && tableCache.TryGet(_tableName, out cached) && useCache) + { + lock (_instanceLock) + { + _isLoaded = true; + _isLoading = false; + Monitor.PulseAll(_instanceLock); + } + return cached as T; // ✅ Atomisk operation! + } + + // Now safe to read - no other thread can access this font's reader + _reader.BaseStream.Position = _offset; + t = LoadInternal(); + } + + // Third: Update cache + lock (_instanceLock) + { + if (tableCache != null && !tableCache.Contains(_tableName)) + { + tableCache.Add(_tableName, t); + } + + _isLoaded = true; + _isLoading = false; + Monitor.PulseAll(_instanceLock); + } + + return t; + } + + public void SetTable(string tableName, T value) + { + tableCache.AddOrReplace(tableName, value); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableLoaderCache.cs b/src/EPPlus.Fonts.OpenType/Tables/TableLoaderCache.cs new file mode 100644 index 0000000000..6f1158403a --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableLoaderCache.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/14/2026 EPPlus Software AB Loader cache for thread safety + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Hhea; +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using EPPlus.Fonts.OpenType.Tables.Kern; +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using EPPlus.Fonts.OpenType.Tables.Name; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.Tables.Post; +using EPPlus.Fonts.OpenType.Tables.Vmtx; + +namespace EPPlus.Fonts.OpenType.Tables +{ + /// + /// Cache for TableLoader instances to ensure thread-safe access. + /// Each OpenTypeFont instance has its own loader cache. + /// + internal class TableLoaderCache + { + private readonly object _lock = new object(); + + public LocaTableLoader LocaLoader; + public HeadTableLoader HeadLoader; + public CmapTableLoader CmapLoader; + public GlyfTableLoader GlyfLoader; + public Os2TableLoader Os2Loader; + public HheaTableLoader HheaLoader; + public VheaTableLoader VheaLoader; + public MaxpTableLoader MaxpLoader; + public HmtxTableLoader HmtxLoader; + public VmtxTableLoader VmtxLoader; + public NameTableLoader NameLoader; + public KernTableLoader KernLoader; + public PostTableLoader PostLoader; + public GsubTableLoader GsubLoader; + public GposTableLoader GposLoader; + + internal object SyncLock { get { return _lock; } } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableLoaderSettings.cs b/src/EPPlus.Fonts.OpenType/Tables/TableLoaderSettings.cs new file mode 100644 index 0000000000..6376aa6e1d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableLoaderSettings.cs @@ -0,0 +1,38 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/14/2026 EPPlus Software AB Added loader cache reference + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables +{ + internal class TableLoaderSettings + { + internal Dictionary _tableRecordsRef { get; private set; } + internal TableCache _tblCacheRef { get; private set; } + internal TableLoaderCache _loaderCacheRef { get; private set; } + + internal FontTableReaderFactory TableReaderFactory { get; private set; } + + internal TableLoaderSettings( + FontTableReaderFactory tableReaderFactory, + Dictionary records, + TableCache tblCache, + TableLoaderCache loaderCache) + { + TableReaderFactory = tableReaderFactory; + _tableRecordsRef = records; + _tblCacheRef = tblCache; + _loaderCacheRef = loaderCache; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableLoaders.cs b/src/EPPlus.Fonts.OpenType/Tables/TableLoaders.cs new file mode 100644 index 0000000000..ff51f42aa5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableLoaders.cs @@ -0,0 +1,228 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 01/14/2026 EPPlus Software AB Cache loader instances for thread safety + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlus.Fonts.OpenType.Tables.Glyph; +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Head; +using EPPlus.Fonts.OpenType.Tables.Hhea; +using EPPlus.Fonts.OpenType.Tables.Hmtx; +using EPPlus.Fonts.OpenType.Tables.Kern; +using EPPlus.Fonts.OpenType.Tables.Loca; +using EPPlus.Fonts.OpenType.Tables.Maxp; +using EPPlus.Fonts.OpenType.Tables.Name; +using EPPlus.Fonts.OpenType.Tables.Os2; +using EPPlus.Fonts.OpenType.Tables.Post; +using EPPlus.Fonts.OpenType.Tables.Vmtx; + +namespace EPPlus.Fonts.OpenType.Tables +{ + internal static class TableLoaders + { + public static LocaTableLoader GetLocaTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.LocaLoader == null) + { + cache.LocaLoader = new LocaTableLoader(settings); + } + return cache.LocaLoader; + } + } + + public static HeadTableLoader GetHeadTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.HeadLoader == null) + { + cache.HeadLoader = new HeadTableLoader(settings); + } + return cache.HeadLoader; + } + } + + public static CmapTableLoader GetCmapTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.CmapLoader == null) + { + cache.CmapLoader = new CmapTableLoader(settings); + } + return cache.CmapLoader; + } + } + + public static GlyfTableLoader GetGlyfTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.GlyfLoader == null) + { + cache.GlyfLoader = new GlyfTableLoader(settings); + } + return cache.GlyfLoader; + } + } + + public static Os2TableLoader GetOs2TableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.Os2Loader == null) + { + cache.Os2Loader = new Os2TableLoader(settings); + } + return cache.Os2Loader; + } + } + + public static HheaTableLoader GetHheaTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.HheaLoader == null) + { + cache.HheaLoader = new HheaTableLoader(settings); + } + return cache.HheaLoader; + } + } + + public static VheaTableLoader GetVheaTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.VheaLoader == null) + { + cache.VheaLoader = new VheaTableLoader(settings); + } + return cache.VheaLoader; + } + } + + public static MaxpTableLoader GetMaxpTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.MaxpLoader == null) + { + cache.MaxpLoader = new MaxpTableLoader(settings); + } + return cache.MaxpLoader; + } + } + + public static HmtxTableLoader GetHmtxTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.HmtxLoader == null) + { + cache.HmtxLoader = new HmtxTableLoader(settings); + } + return cache.HmtxLoader; + } + } + + public static VmtxTableLoader GetVmtxTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.VmtxLoader == null) + { + cache.VmtxLoader = new VmtxTableLoader(settings); + } + return cache.VmtxLoader; + } + } + + public static NameTableLoader GetNameTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.NameLoader == null) + { + cache.NameLoader = new NameTableLoader(settings); + } + return cache.NameLoader; + } + } + + public static KernTableLoader GetKernTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.KernLoader == null) + { + cache.KernLoader = new KernTableLoader(settings); + } + return cache.KernLoader; + } + } + + public static PostTableLoader GetPostTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.PostLoader == null) + { + cache.PostLoader = new PostTableLoader(settings); + } + return cache.PostLoader; + } + } + + public static GsubTableLoader GetGsubTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.GsubLoader == null) + { + cache.GsubLoader = new GsubTableLoader(settings); + } + return cache.GsubLoader; + } + } + + public static GposTableLoader GetGposTableLoader(TableLoaderSettings settings) + { + var cache = settings._loaderCacheRef; + lock (cache.SyncLock) + { + if (cache.GposLoader == null) + { + cache.GposLoader = new GposTableLoader(settings); + } + return cache.GposLoader; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/TableNames.cs b/src/EPPlus.Fonts.OpenType/Tables/TableNames.cs new file mode 100644 index 0000000000..150a827f24 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/TableNames.cs @@ -0,0 +1,33 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables +{ + internal static class TableNames + { + public const string Glyf = "glyf"; + public const string Head = "head"; + public const string Loca = "loca"; + public const string Os2 = "OS/2"; + public const string Hhea = "hhea"; + public const string Hmtx = "hmtx"; + public const string Vhea = "vhea"; + public const string Vmtx = "vmtx"; + public const string Maxp = "maxp"; + public const string Name = "name"; + public const string Kern = "kern"; + public const string Post = "post"; + public const string Cmap = "cmap"; + public const string Gsub = "GSUB"; + public const string Gpos = "GPOS"; + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Version16Dot16.cs b/src/EPPlus.Fonts.OpenType/Tables/Version16Dot16.cs new file mode 100644 index 0000000000..754492db65 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Version16Dot16.cs @@ -0,0 +1,55 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Tables; + +public class Version16Dot16 : FontTableElement +{ + public Version16Dot16(int value) + { + RawValue = value; + Major = (value >> 16) & 0xFFFF; + Minor = value & 0xFFFF; + FloatValue = Major + (Minor / 65536f); + } + + /// + /// Raw 32-bit packed value + /// + public int RawValue { get; } + + /// + /// Major version (upper 16 bits) + /// + public int Major { get; } + + /// + /// Minor version (lower 16 bits) + /// + public int Minor { get; } + + /// + /// Version as float (e.g. 1.5f for 0x00018000) + /// + public float FloatValue { get; } + + public override string ToString() + { + return $"{Major}.{FloatValue - Major:F4}"; + } + + internal override void Serialize(FontsBinaryWriter writer) + { + writer.WriteInt32BigEndian(RawValue); + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTable.cs new file mode 100644 index 0000000000..d04cf607fc --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTable.cs @@ -0,0 +1,172 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/18/2026 EPPlus Software AB vhea table implementation (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; + +namespace EPPlus.Fonts.OpenType.Tables.Vhea +{ + /// + /// Represents the OpenType 'vhea' (Vertical Header) table. + /// Contains global metrics for vertically laid-out fonts (primarily CJK). + /// Structurally identical to 'hhea' but for the vertical axis. + /// Source: https://learn.microsoft.com/en-us/typography/opentype/spec/vhea + /// + public class VheaTable : FontTableBase + { + public override string Name => TableNames.Vhea; + + /// + /// Optional table - only present in fonts with vertical metrics (primarily CJK fonts). + /// + public override bool IsEssentialTable => false; + + // --- Version --- + + /// + /// Table version. Either 0x00011000 (version 1.1) or 0x00010000 (version 1.0). + /// Version 1.1 renamed some fields; the binary layout is identical. + /// + public uint Version { get; set; } + + // --- Vertical metrics (version 1.1 names; version 1.0 names in comments) --- + + /// + /// The vertical typographic ascender for the font. (v1.0: ascent) + /// Typically a positive value equal to half the em square. + /// + public short Ascent { get; set; } + + /// + /// The vertical typographic descender for the font. (v1.0: descent) + /// Typically a negative value equal to minus half the em square. + /// + public short Descent { get; set; } + + /// + /// Additional line spacing for vertical layout. (v1.0: lineGap) + /// + public short LineGap { get; set; } + + /// + /// Maximum advance height across all glyphs in the font. + /// + public short AdvanceHeightMax { get; set; } + + /// + /// Minimum top side bearing across all glyphs with contours. + /// + public short MinTopSideBearing { get; set; } + + /// + /// Minimum bottom side bearing across all glyphs with contours. + /// Calculated as: advanceHeight - (tsb + yMin - yMax) + /// + public short MinBottomSideBearing { get; set; } + + /// + /// Maximum extent: max(tsb + (yMax - yMin)) across all glyphs with contours. + /// + public short YMaxExtent { get; set; } + + /// + /// The rise of the caret slope for vertical text (used to draw the caret). + /// For vertical text: typically 0. + /// + public short CaretSlopeRise { get; set; } + + /// + /// The run of the caret slope for vertical text. + /// For vertical text: typically 1. + /// + public short CaretSlopeRun { get; set; } + + /// + /// Offset of the caret from the glyph origin. Set to 0 for non-slanted fonts. + /// + public short CaretOffset { get; set; } + + // Reserved fields (must be 0 per spec) + public short Reserved1 { get; set; } + public short Reserved2 { get; set; } + public short Reserved3 { get; set; } + public short Reserved4 { get; set; } + + /// + /// Set to 0. (Kept for future use per spec.) + /// + public short MetricDataFormat { get; set; } + + /// + /// Number of LongVerMetric entries in the 'vmtx' table. + /// Controls how vmtx is parsed - analogous to hhea.numberOfHMetrics. + /// + public ushort NumberOfVMetrics { get; set; } + + // --- Clone --- + + /// + /// Creates a deep copy of this VheaTable. + /// Used during font subsetting - NumberOfVMetrics will be updated by VheaSubsetProcessor. + /// + public VheaTable Clone() + { + return new VheaTable + { + Version = Version, + Ascent = Ascent, + Descent = Descent, + LineGap = LineGap, + AdvanceHeightMax = AdvanceHeightMax, + MinTopSideBearing = MinTopSideBearing, + MinBottomSideBearing = MinBottomSideBearing, + YMaxExtent = YMaxExtent, + CaretSlopeRise = CaretSlopeRise, + CaretSlopeRun = CaretSlopeRun, + CaretOffset = CaretOffset, + Reserved1 = Reserved1, + Reserved2 = Reserved2, + Reserved3 = Reserved3, + Reserved4 = Reserved4, + MetricDataFormat = MetricDataFormat, + NumberOfVMetrics = NumberOfVMetrics + }; + } + + // --- Serialization --- + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + writer.WriteUInt32BigEndian(Version); + writer.WriteInt16BigEndian(Ascent); + writer.WriteInt16BigEndian(Descent); + writer.WriteInt16BigEndian(LineGap); + writer.WriteInt16BigEndian(AdvanceHeightMax); + writer.WriteInt16BigEndian(MinTopSideBearing); + writer.WriteInt16BigEndian(MinBottomSideBearing); + writer.WriteInt16BigEndian(YMaxExtent); + writer.WriteInt16BigEndian(CaretSlopeRise); + writer.WriteInt16BigEndian(CaretSlopeRun); + writer.WriteInt16BigEndian(CaretOffset); + writer.WriteInt16BigEndian(Reserved1); + writer.WriteInt16BigEndian(Reserved2); + writer.WriteInt16BigEndian(Reserved3); + writer.WriteInt16BigEndian(Reserved4); + writer.WriteInt16BigEndian(MetricDataFormat); + writer.WriteUInt16BigEndian(NumberOfVMetrics); + } + + internal override void Clear() + { + // Not used in current architecture + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableLoader.cs new file mode 100644 index 0000000000..59188a9259 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableLoader.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/18/2026 EPPlus Software AB vhea table implementation (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Vhea; + +namespace EPPlus.Fonts.OpenType.Tables +{ + internal class VheaTableLoader : TableLoader + { + public VheaTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Vhea) + { + } + + protected override VheaTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + + var table = new VheaTable(); + + // Version is a Fixed (uint32): 0x00011000 = v1.1, 0x00010000 = v1.0 + table.Version = _reader.ReadUInt32BigEndian(); + table.Ascent = _reader.ReadInt16BigEndian(); + table.Descent = _reader.ReadInt16BigEndian(); + table.LineGap = _reader.ReadInt16BigEndian(); + table.AdvanceHeightMax = _reader.ReadInt16BigEndian(); + table.MinTopSideBearing = _reader.ReadInt16BigEndian(); + table.MinBottomSideBearing = _reader.ReadInt16BigEndian(); + table.YMaxExtent = _reader.ReadInt16BigEndian(); + table.CaretSlopeRise = _reader.ReadInt16BigEndian(); + table.CaretSlopeRun = _reader.ReadInt16BigEndian(); + table.CaretOffset = _reader.ReadInt16BigEndian(); + table.Reserved1 = _reader.ReadInt16BigEndian(); + table.Reserved2 = _reader.ReadInt16BigEndian(); + table.Reserved3 = _reader.ReadInt16BigEndian(); + table.Reserved4 = _reader.ReadInt16BigEndian(); + table.MetricDataFormat = _reader.ReadInt16BigEndian(); + table.NumberOfVMetrics = _reader.ReadUInt16BigEndian(); + + return table; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableValidator.cs new file mode 100644 index 0000000000..40fc43bf4c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vhea/VheaTableValidator.cs @@ -0,0 +1,113 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/18/2026 EPPlus Software AB vhea table implementation (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; + +namespace EPPlus.Fonts.OpenType.Tables.Vhea +{ + /// + /// Validates the 'vhea' (Vertical Header) table. + /// This is an optional table, only present in fonts with vertical metrics (primarily CJK). + /// + internal class VheaTableValidator : TableValidatorBase + { + public override Type TableType => typeof(VheaTable); + public override string TableName => TableNames.Vhea; + + public override TableValidationResult Validate(VheaTable table, FontValidationContext context) + { + var result = new TableValidationResult { TableName = TableName, LogLevel = base.LogLevel }; + + // 1. Version check: must be 1.0 (0x00010000) or 1.1 (0x00011000) + if (table.Version != 0x00010000 && table.Version != 0x00011000) + { + result.AddMessage(FontValidationSeverity.Warning, + $"vhea version is 0x{table.Version:X8}. Expected 0x00010000 (v1.0) or 0x00011000 (v1.1)."); + } + + // 2. Ascent and Descent should not be zero individually + if (table.Ascent == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "Ascent is 0, which is unusual."); + } + if (table.Descent == 0) + { + result.AddMessage(FontValidationSeverity.Warning, "Descent is 0, which is unusual."); + } + + // 3. Sanity-check against unitsPerEm + var head = context.Font.HeadTable; + if (head != null) + { + int totalHeight = table.Ascent - table.Descent; + if (totalHeight > head.UnitsPerEm * 2) + { + result.AddMessage(FontValidationSeverity.Warning, + $"vhea total height (Ascent - Descent = {totalHeight}) is more than 2x unitsPerEm ({head.UnitsPerEm}). This is unusual."); + } + } + + // 3. LineGap can be negative but usually >= 0 + if (table.LineGap < 0) + { + result.AddMessage(FontValidationSeverity.Information, + $"LineGap is negative ({table.LineGap}). Some platforms treat negative as zero."); + } + + // 4. AdvanceHeightMax must be positive + if (table.AdvanceHeightMax == 0) + { + result.AddMessage(FontValidationSeverity.Error, "AdvanceHeightMax is 0, which is invalid."); + } + + if (head != null && table.AdvanceHeightMax > head.UnitsPerEm * 2) + { + result.AddMessage(FontValidationSeverity.Warning, + $"AdvanceHeightMax ({table.AdvanceHeightMax}) seems unusually large compared to HeadTable.UnitsPerEm ({head.UnitsPerEm})."); + } + + // 5. MetricDataFormat must be 0 (only defined value per spec) + if (table.MetricDataFormat != 0) + { + result.AddMessage(FontValidationSeverity.Error, + $"vhea.MetricDataFormat is {table.MetricDataFormat}. Only 0 is defined by the spec."); + } + + // 6. NumberOfVMetrics must be > 0 and consistent with maxp.numGlyphs + if (table.NumberOfVMetrics == 0) + { + result.AddMessage(FontValidationSeverity.Error, + "vhea.NumberOfVMetrics is 0. The vmtx table cannot be parsed without at least one entry."); + } + else + { + var maxp = context.Font.MaxpTable; + if (maxp != null && table.NumberOfVMetrics > maxp.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"vhea.NumberOfVMetrics ({table.NumberOfVMetrics}) exceeds maxp.numGlyphs ({maxp.numGlyphs}). Font is likely corrupt."); + } + } + + // 7. Reserved fields should be 0 + if (table.Reserved1 != 0 || table.Reserved2 != 0 || + table.Reserved3 != 0 || table.Reserved4 != 0) + { + result.AddMessage(FontValidationSeverity.Warning, + "One or more vhea reserved fields are non-zero. These should be 0 per spec."); + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vmtx/LongVerMetric.cs b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/LongVerMetric.cs new file mode 100644 index 0000000000..1cf0edd9af --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/LongVerMetric.cs @@ -0,0 +1,33 @@ + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vmtx table implementation (vertical text support) + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Tables.Vmtx +{ + /// + /// Represents a single entry in the vmtx table's longVerMetric array. + /// Analogous to LongHorMetric in hmtx. + /// + public class LongVerMetric + { + /// + /// The advance height of the glyph in font design units. + /// + public ushort AdvanceHeight { get; set; } + + /// + /// The top side bearing of the glyph in font design units. + /// Distance from the vertical origin to the top of the glyph bounding box. + /// + public short TopSideBearing { get; set; } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTable.cs b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTable.cs new file mode 100644 index 0000000000..af7cc1cc5b --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTable.cs @@ -0,0 +1,125 @@ + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vmtx table implementation (vertical text support) + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Vmtx +{ + /// + /// Represents the 'vmtx' (Vertical Metrics) table. + /// Contains advance heights and top side bearings for each glyph. + /// Only present in fonts with vertical layout support (primarily CJK). + /// Analogous to the 'hmtx' table for horizontal metrics. + /// + public class VmtxTable : FontTableBase + { + public VmtxTable() { } + + public VmtxTable(List vMetrics) + { + VMetrics = vMetrics; + TopSideBearings = new List(); + } + + public VmtxTable(List vMetrics, List topSideBearings) + { + VMetrics = vMetrics; + TopSideBearings = topSideBearings; + } + + /// + /// Array of longVerMetric records, one per glyph up to numberOfVMetrics. + /// Each record contains advanceHeight and topSideBearing. + /// + public List VMetrics { get; set; } = new List(); + + /// + /// Additional top side bearings for glyphs beyond numberOfVMetrics. + /// These glyphs share the last advanceHeight in VMetrics. + /// Count = maxp.numGlyphs - vhea.numberOfVMetrics. + /// + public List TopSideBearings { get; set; } = new List(); + + public override string Name => TableNames.Vmtx; + public override bool IsEssentialTable => false; + + /// + /// Gets the advance height for a given glyph ID. + /// If the glyph ID is beyond the VMetrics array, the last entry's advanceHeight is used + /// (per OpenType spec). + /// + public ushort GetAdvanceHeight(ushort glyphId) + { + if (VMetrics == null || VMetrics.Count == 0) + return 0; + + if (glyphId < VMetrics.Count) + return VMetrics[glyphId].AdvanceHeight; + + // Glyphs beyond numberOfVMetrics share the last advanceHeight + return VMetrics[VMetrics.Count - 1].AdvanceHeight; + } + + /// + /// Gets the top side bearing for a given glyph ID. + /// Checks VMetrics first, then the TopSideBearings array. + /// + public short GetTopSideBearing(ushort glyphId) + { + if (VMetrics == null || VMetrics.Count == 0) + return 0; + + if (glyphId < VMetrics.Count) + return VMetrics[glyphId].TopSideBearing; + + // Look in the additional TopSideBearings array + int tsb_idx = glyphId - VMetrics.Count; + if (TopSideBearings != null && tsb_idx < TopSideBearings.Count) + return TopSideBearings[tsb_idx]; + + return 0; + } + + /// + /// Creates a deep copy of this VmtxTable. + /// Used during font subsetting. + /// + public VmtxTable Clone() + { + var clonedMetrics = new List(VMetrics.Count); + foreach (var m in VMetrics) + clonedMetrics.Add(new LongVerMetric { AdvanceHeight = m.AdvanceHeight, TopSideBearing = m.TopSideBearing }); + + var clonedTsb = new List(TopSideBearings); + return new VmtxTable(clonedMetrics, clonedTsb); + } + + internal override void SerializeInternal(FontsBinaryWriter writer, FontSerializationContext context) + { + foreach (var m in VMetrics) + { + writer.WriteUInt16BigEndian(m.AdvanceHeight); + writer.WriteInt16BigEndian(m.TopSideBearing); + } + foreach (var tsb in TopSideBearings) + { + writer.WriteInt16BigEndian(tsb); + } + } + + internal override void Clear() + { + // Not used in current architecture + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableLoader.cs b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableLoader.cs new file mode 100644 index 0000000000..6d75c9420f --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableLoader.cs @@ -0,0 +1,61 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vmtx table implementation (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Vmtx; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Tables.Vmtx +{ + /// + /// Loads the 'vmtx' (Vertical Metrics) table. + /// Requires vhea.numberOfVMetrics and maxp.numGlyphs to determine the table layout, + /// analogous to how HmtxTableLoader uses hhea.numberOfHMetrics. + /// + internal class VmtxTableLoader : TableLoader + { + private readonly int _numberOfVMetrics; + private readonly int _numGlyphs; + + public VmtxTableLoader(TableLoaderSettings settings) : base(settings, TableNames.Vmtx) + { + _numberOfVMetrics = TableLoaders.GetVheaTableLoader(settings).Load().NumberOfVMetrics; + _numGlyphs = TableLoaders.GetMaxpTableLoader(settings).Load().numGlyphs; + } + + protected override VmtxTable LoadInternal() + { + _reader.BaseStream.Position = _offset; + + // Read longVerMetric array (numberOfVMetrics entries) + var vMetrics = new List(_numberOfVMetrics); + for (int i = 0; i < _numberOfVMetrics; i++) + { + vMetrics.Add(new LongVerMetric + { + AdvanceHeight = _reader.ReadUInt16BigEndian(), + TopSideBearing = _reader.ReadInt16BigEndian() + }); + } + + // Read additional topSideBearing entries for remaining glyphs. + // Count = numGlyphs - numberOfVMetrics + int extraTsbCount = _numGlyphs - _numberOfVMetrics; + var topSideBearings = new List(extraTsbCount > 0 ? extraTsbCount : 0); + for (int i = 0; i < extraTsbCount; i++) + { + topSideBearings.Add(_reader.ReadInt16BigEndian()); + } + + return new VmtxTable(vMetrics, topSideBearings); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableValidator.cs b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableValidator.cs new file mode 100644 index 0000000000..e887f4abad --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tables/Vmtx/VmtxTableValidator.cs @@ -0,0 +1,92 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB vmtx table implementation (vertical text support) + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.FontValidation; +using System; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.Tables.Vmtx +{ + /// + /// Validates the 'vmtx' (Vertical Metrics) table. + /// This is an optional table, only present in fonts with vertical metrics (primarily CJK). + /// Analogous to HmtxTableValidator. + /// + internal class VmtxTableValidator : TableValidatorBase + { + public override Type TableType => typeof(VmtxTable); + public override string TableName => TableNames.Vmtx; + + public override TableValidationResult Validate(VmtxTable table, FontValidationContext context) + { + var result = new TableValidationResult { TableName = TableName, LogLevel = base.LogLevel }; + + var vhea = context.Font.VheaTable; + var maxp = context.Font.MaxpTable; + + // 1. vhea is required to interpret vmtx + if (vhea == null) + { + result.AddMessage(FontValidationSeverity.Error, + "vmtx table is present but vhea table is missing. Cannot validate vmtx without vhea."); + return result; + } + + // 2. VMetrics count must match vhea.NumberOfVMetrics + int vMetricsCount = table.VMetrics?.Count ?? 0; + if (vMetricsCount != vhea.NumberOfVMetrics) + { + result.AddMessage(FontValidationSeverity.Error, + $"vmtx.VMetrics count ({vMetricsCount}) does not match vhea.NumberOfVMetrics ({vhea.NumberOfVMetrics})."); + } + + // 3. Total glyph coverage must equal maxp.numGlyphs + if (maxp != null) + { + int tsbCount = table.TopSideBearings?.Count ?? 0; + int totalCoverage = vMetricsCount + tsbCount; + if (totalCoverage != maxp.numGlyphs) + { + result.AddMessage(FontValidationSeverity.Error, + $"vmtx total glyph coverage ({totalCoverage}) does not match maxp.numGlyphs ({maxp.numGlyphs}). " + + $"VMetrics ({vMetricsCount}) + TopSideBearings ({tsbCount}) should equal {maxp.numGlyphs}."); + } + } + + // 4. All advance heights must be > 0 + if (table.VMetrics != null) + { + for (int i = 0; i < table.VMetrics.Count; i++) + { + if (table.VMetrics[i].AdvanceHeight == 0) + { + result.AddMessage(FontValidationSeverity.Warning, + $"vmtx.VMetrics[{i}].AdvanceHeight is 0, which is unusual."); + } + } + } + + // 5. AdvanceHeightMax in vhea should match the actual max in vmtx + if (table.VMetrics != null && table.VMetrics.Count > 0) + { + ushort maxAdvanceHeight = table.VMetrics.Max(m => m.AdvanceHeight); + if (vhea.AdvanceHeightMax < maxAdvanceHeight) + { + result.AddMessage(FontValidationSeverity.Error, + $"vhea.AdvanceHeightMax ({vhea.AdvanceHeightMax}) is less than the actual max advanceHeight in vmtx ({maxAdvanceHeight})."); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Tag.cs b/src/EPPlus.Fonts.OpenType/Tag.cs new file mode 100644 index 0000000000..6df7cc4f49 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Tag.cs @@ -0,0 +1,73 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.IO; +using System; +using EPPlus.Fonts.OpenType.Tables; + +namespace EPPlus.Fonts.OpenType +{ + public class Tag : FontTableElement + { + internal Tag(BinaryReader reader) + { + var b1 = reader.ReadByte(); + var b2 = reader.ReadByte(); + var b3 = reader.ReadByte(); + var b4 = reader.ReadByte(); + + var c1 = Convert.ToChar(b1); + var c2 = Convert.ToChar(b2); + var c3 = Convert.ToChar(b3); + var c4 = Convert.ToChar(b4); + + Value = new string(new char[] { c1, c2, c3, c4 }); + } + + internal Tag(string value) + { + Value = value; + } + + public string Value { get; private set; } + + internal override void Serialize(FontsBinaryWriter writer) + { + if (Value == null || Value.Length != 4) + throw new InvalidOperationException("Tag must contain exactly 4 characters."); + + foreach (char c in Value) + { + writer.Write((byte)c); // ASCII encoding + } + } + + + /// + /// Converts the tag to a 4-byte ASCII array. + /// + internal byte[] ToBytes() + { + if (Value == null || Value.Length != 4) + throw new InvalidOperationException("Tag must contain exactly 4 characters."); + + return new byte[] + { + (byte)Value[0], + (byte)Value[1], + (byte)Value[2], + (byte)Value[3] + }; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Contextual/ChainingContextualProcessor.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Contextual/ChainingContextualProcessor.cs new file mode 100644 index 0000000000..03dfdd15ac --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Contextual/ChainingContextualProcessor.cs @@ -0,0 +1,419 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using EPPlus.Fonts.OpenType.TextShaping.Ligatures; +using EPPlus.Fonts.OpenType.TextShaping.Substitutions; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Contextual +{ + internal class ChainingContextualProcessor + { + private readonly OpenTypeFont _font; + private readonly SingleSubstitutionProcessor _singleSubstProcessor; + private readonly LigatureProcessor _ligatureProcessor; + + public ChainingContextualProcessor( + OpenTypeFont font, + SingleSubstitutionProcessor singleSubstProcessor, + LigatureProcessor ligatureProcessor) + { + _font = font; + _singleSubstProcessor = singleSubstProcessor; + _ligatureProcessor = ligatureProcessor; + } + + /// + /// Applies chaining contextual substitutions for a specific feature. + /// + internal List ApplyContextualSubstitutions( + List glyphs, + string featureTag) + { + var gsub = _font.GsubTable; + if (gsub == null) + return glyphs; + + // Find all Type 6 lookups for this feature + var contextualLookups = FindContextualLookupsForFeature(gsub, featureTag); + if (contextualLookups.Count == 0) + return glyphs; + + // Apply each lookup in order + foreach (var lookup in contextualLookups) + { + glyphs = ApplyContextualLookup(glyphs, lookup); + } + + return glyphs; + } + + /// + /// Finds all Type 6 lookups associated with a feature tag. + /// + private List FindContextualLookupsForFeature(GsubTable gsub, string featureTag) + { + var lookups = new List(); + + foreach (var featureRecord in gsub.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == featureTag) + { + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < gsub.LookupList.Lookups.Count) + { + var lookup = gsub.LookupList.Lookups[lookupIndex]; + + // Only Type 6 (Chaining Contextual) or Type 7 (Extension wrapping Type 6) + if (lookup.LookupType == 6) + { + lookups.Add(lookup); + } + else if (lookup.LookupType == 7) + { + // Check if extension wraps a Type 6 + foreach (var subtable in lookup.SubTables) + { + if (subtable is ExtensionSubstSubTable ext && + ext.ExtensionLookupType == 6) + { + lookups.Add(lookup); + break; + } + } + } + } + } + } + } + + return lookups; + } + + /// + /// Applies a single chaining contextual lookup to the glyph sequence. + /// + private List ApplyContextualLookup(List glyphs, LookupTable lookup) + { + var result = new List(glyphs); + int i = 0; + + while (i < result.Count) + { + bool substituted = false; + + // Try each subtable + foreach (var subtable in lookup.SubTables) + { + ChainingContextualSubstFormat3 contextual = null; + + if (subtable is ChainingContextualSubstFormat3 format3) + { + contextual = format3; + } + else if (subtable is ExtensionSubstSubTable ext && + ext.ExtendedSubTable is ChainingContextualSubstFormat3 extFormat3) + { + contextual = extFormat3; + } + + if (contextual != null) + { + // Try to match and apply contextual rule at position i + if (TryApplyContextualRule(result, i, contextual, out var newGlyphs, out int glyphsConsumed)) + { + // Replace glyphs at position i with the result + result.RemoveRange(i, glyphsConsumed); + result.InsertRange(i, newGlyphs); + + // Move past the substituted sequence + i += newGlyphs.Count; + substituted = true; + break; + } + } + } + + if (!substituted) + { + i++; + } + } + + return result; + } + + /// + /// Attempts to match and apply a contextual rule starting at the given position. + /// + private bool TryApplyContextualRule( + List glyphs, + int position, + ChainingContextualSubstFormat3 rule, + out List resultGlyphs, + out int glyphsConsumed) + { + resultGlyphs = null; + glyphsConsumed = 0; + + // 1. Check if we have enough glyphs for the complete context + int backtrackCount = rule.BacktrackCoverages?.Count ?? 0; + int inputCount = rule.InputCoverages?.Count ?? 0; + int lookaheadCount = rule.LookaheadCoverages?.Count ?? 0; + + if (inputCount == 0) + return false; + + // Check bounds + if (position < backtrackCount) + return false; + + if (position + inputCount + lookaheadCount > glyphs.Count) + return false; + + // 2. Match backtrack context (in reverse order!) + if (backtrackCount > 0) + { + for (int i = 0; i < backtrackCount; i++) + { + int glyphPos = position - 1 - i; + var coverage = rule.BacktrackCoverages[i]; + + if (coverage.GetGlyphIndex(glyphs[glyphPos].GlyphId) < 0) + return false; // Backtrack mismatch + } + } + + // 3. Match input sequence + for (int i = 0; i < inputCount; i++) + { + int glyphPos = position + i; + var coverage = rule.InputCoverages[i]; + + if (coverage.GetGlyphIndex(glyphs[glyphPos].GlyphId) < 0) + return false; // Input mismatch + } + + // 4. Match lookahead context + if (lookaheadCount > 0) + { + for (int i = 0; i < lookaheadCount; i++) + { + int glyphPos = position + inputCount + i; + var coverage = rule.LookaheadCoverages[i]; + + if (coverage.GetGlyphIndex(glyphs[glyphPos].GlyphId) < 0) + return false; // Lookahead mismatch + } + } + + // 5. Context matches! Apply the substitution lookups + var inputGlyphs = glyphs.GetRange(position, inputCount); + + foreach (var substRecord in rule.SubstLookupRecords) + { + if (substRecord.SequenceIndex >= inputCount) + continue; // Invalid record + + // Get the lookup to apply + var gsub = _font.GsubTable; + if (substRecord.LookupListIndex >= gsub.LookupList.Lookups.Count) + continue; + + var targetLookup = gsub.LookupList.Lookups[substRecord.LookupListIndex]; + + // Apply the lookup to the input sequence + inputGlyphs = ApplyReferencedLookup(inputGlyphs, targetLookup, substRecord.SequenceIndex); + } + + resultGlyphs = inputGlyphs; + glyphsConsumed = inputCount; + return true; + } + + /// + /// Applies a referenced lookup (Type 1, Type 4, etc.) to a glyph sequence. + /// + private List ApplyReferencedLookup( + List glyphs, + LookupTable lookup, + int startPosition) + { + // Get the actual lookup type (unwrap Extension if needed) + ushort lookupType = lookup.LookupType; + List subtables = lookup.SubTables; + + if (lookupType == 7 && subtables.Count > 0 && subtables[0] is ExtensionSubstSubTable ext) + { + lookupType = ext.ExtensionLookupType; + subtables = new List { ext.ExtendedSubTable }; + } + + switch (lookupType) + { + case 1: // Single Substitution + return ApplySingleSubstitutionAtPosition(glyphs, subtables, startPosition); + + case 4: // Ligature Substitution + return ApplyLigatureSubstitutionAtPosition(glyphs, subtables, startPosition); + + default: + // Unsupported lookup type in contextual rule + return glyphs; + } + } + + /// + /// Applies Type 1 Single Substitution at a specific position. + /// + private List ApplySingleSubstitutionAtPosition( + List glyphs, + List subtables, + int position) + { + if (position >= glyphs.Count) + return glyphs; + + foreach (var subtable in subtables) + { + if (subtable is SingleSubstSubTable singleSubst) + { + ushort oldGlyphId = glyphs[position].GlyphId; + + var newGlyphId = singleSubst.GetSubstitution(oldGlyphId); + if (newGlyphId > 0) + { + var result = new List(glyphs); + result[position] = CreateSubstitutedGlyph(glyphs[position], newGlyphId); + return result; + } + } + } + + return glyphs; + } + + /// + /// Applies Type 4 Ligature Substitution starting at a specific position. + /// + private List ApplyLigatureSubstitutionAtPosition( + List glyphs, + List subtables, + int position) + { + if (position >= glyphs.Count) + return glyphs; + + foreach (var subtable in subtables) + { + if (subtable is LigatureSubstSubTable ligSubtable) + { + ushort firstGlyph = glyphs[position].GlyphId; + + // Check coverage + int coverageIndex = ligSubtable.Coverage.GetGlyphIndex(firstGlyph); + if (coverageIndex < 0) + continue; + + if (!ligSubtable.LigatureSets.TryGetValue(firstGlyph, out var ligatureSet)) + continue; + + if (ligatureSet?.Ligatures == null) + continue; + + // Try each ligature + foreach (var ligature in ligatureSet.Ligatures) + { + int componentCount = 1 + (ligature.Components?.Length ?? 0); + + if (position + componentCount > glyphs.Count) + continue; + + // Check if components match + bool matches = true; + if (ligature.Components != null) + { + for (int i = 0; i < ligature.Components.Length; i++) + { + if (glyphs[position + 1 + i].GlyphId != ligature.Components[i]) + { + matches = false; + break; + } + } + } + + if (matches) + { + // Create ligature + var result = new List(glyphs); + var ligatureGlyph = CreateLigatureGlyph(glyphs, position, (byte)componentCount, ligature.LigatureGlyph); + + result.RemoveRange(position, componentCount); + result.Insert(position, ligatureGlyph); + + return result; + } + } + } + } + + return glyphs; + } + + private ShapedGlyph CreateSubstitutedGlyph(ShapedGlyph original, ushort newGlyphId) + { + var baseAdvance = (short)_font.HmtxTable.GetAdvanceWidth(newGlyphId); + + return new ShapedGlyph + { + GlyphId = newGlyphId, + BaseAdvance = baseAdvance, // ← New base advance for substituted glyph + XAdvance = baseAdvance, // ← Reset to base (kerning will be reapplied) + YAdvance = 0, + XOffset = 0, + YOffset = 0, + ClusterIndex = original.ClusterIndex, + CharCount = original.CharCount + }; + } + + private ShapedGlyph CreateLigatureGlyph( + List glyphs, + int startIndex, + byte componentCount, + ushort ligatureGlyphId) + { + var baseAdvance = (short)_font.HmtxTable.GetAdvanceWidth(ligatureGlyphId); + var clusterIndex = glyphs[startIndex].ClusterIndex; + + return new ShapedGlyph + { + GlyphId = ligatureGlyphId, + BaseAdvance = baseAdvance, // ← Base advance for ligature + XAdvance = baseAdvance, // ← Will be adjusted by positioning + YAdvance = 0, + XOffset = 0, + YOffset = 0, + ClusterIndex = clusterIndex, + CharCount = componentCount + }; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/GposKerningProvider.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/GposKerningProvider.cs new file mode 100644 index 0000000000..0ddb5847c2 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/GposKerningProvider.cs @@ -0,0 +1,82 @@ +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType2; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Kerning +{ + /// + /// Provides kerning from GPOS PairPos lookups (Type 2). + /// Supports both Format 1 (individual pairs) and Format 2 (class-based). + /// Uses lazy per-query lookup via TryGetPairAdjustment instead of + /// pre-expanding all possible glyph pairs. + /// + internal class GposKerningProvider + { + private readonly List _subtables; + + public GposKerningProvider(GposTable gposTable) + { + _subtables = FindAllKerningSubtables(gposTable); + } + + /// + /// Gets kerning adjustment for a glyph pair. + /// Delegates to PairPosSubTable.TryGetPairAdjustment which does: + /// Format 1: coverage lookup + binary search in PairSet — O(log n) + /// Format 2: coverage lookup + class lookup + matrix index — O(1) + /// Combined with KerningCache in KerningProvider, each unique pair + /// is looked up at most once. + /// + public short GetKerning(ushort leftGlyph, ushort rightGlyph) + { + for (int i = 0; i < _subtables.Count; i++) + { + if (_subtables[i].TryGetPairAdjustment(leftGlyph, rightGlyph, + out var value1, out var value2)) + { + if (value1 != null && value1.XAdvance != 0) + return value1.XAdvance; + } + } + + return 0; + } + + private List FindAllKerningSubtables(GposTable gpos) + { + var subtables = new List(); + + if (gpos == null) + return subtables; + + foreach (var featureRecord in gpos.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "kern") + { + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex >= gpos.LookupList.Lookups.Count) + continue; + + var lookup = gpos.LookupList.Lookups[lookupIndex]; + + if (lookup.LookupType == 2) + { + foreach (var subtable in lookup.SubTables) + { + if (subtable is PairPosSubTable pairPos) + { + subtables.Add(pairPos); + } + } + } + } + } + } + + return subtables; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningCache.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningCache.cs new file mode 100644 index 0000000000..67b63b55f0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningCache.cs @@ -0,0 +1,61 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Kerning +{ + /// + /// Caches kerning values for glyph pairs to avoid repeated lookups. + /// + internal class KerningCache + { + private readonly Dictionary _cache; + + public KerningCache() + { + _cache = new Dictionary(); + } + + /// + /// Tries to get a cached kerning value. + /// + public bool TryGet(ushort leftGlyph, ushort rightGlyph, out short value) + { + ulong key = MakeKey(leftGlyph, rightGlyph); + return _cache.TryGetValue(key, out value); + } + + /// + /// Caches a kerning value. + /// + public void Set(ushort leftGlyph, ushort rightGlyph, short value) + { + ulong key = MakeKey(leftGlyph, rightGlyph); + _cache[key] = value; + } + + /// + /// Clears the cache. + /// + public void Clear() + { + _cache.Clear(); + } + + private static ulong MakeKey(ushort leftGlyph, ushort rightGlyph) + { + // Combine two ushorts into one ulong for fast dictionary lookup + return ((ulong)leftGlyph << 16) | rightGlyph; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningProvider.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningProvider.cs new file mode 100644 index 0000000000..13fb4368d0 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/KerningProvider.cs @@ -0,0 +1,82 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using System; +using System.Runtime.CompilerServices; + +namespace EPPlus.Fonts.OpenType.TextShaping.Kerning +{ + /// + /// Provides kerning adjustments for glyph pairs. + /// Delegates to GPOS (modern) or legacy kern table. + /// + internal class KerningProvider + { + private readonly GposKerningProvider _gposProvider; + private readonly LegacyKerningProvider _legacyProvider; + private readonly KerningCache _cache; + + + public KerningProvider(OpenTypeFont font) + { + _cache = new KerningCache(); + + if (font.GposTable != null) + { + _gposProvider = new GposKerningProvider(font.GposTable); + } + + if (font.KernTable != null) + _legacyProvider = new LegacyKerningProvider(font.KernTable); + } + + /// + /// Gets kerning value for a glyph pair. + /// Returns 0 if no kerning is defined. + /// + public short GetKerning(ushort leftGlyph, ushort rightGlyph) + { + // Check cache first + if (_cache.TryGet(leftGlyph, rightGlyph, out short cachedValue)) + return cachedValue; + + // Lookup kerning value + short kernValue = LookupKerning(leftGlyph, rightGlyph); + + // Cache result + _cache.Set(leftGlyph, rightGlyph, kernValue); + + return kernValue; + } + + public void ClearCache() => _cache.Clear(); + + private short LookupKerning(ushort leftGlyph, ushort rightGlyph) + { + // Try GPOS first (modern, preferred) + if (_gposProvider != null) + { + short gposKern = _gposProvider.GetKerning(leftGlyph, rightGlyph); + if (gposKern != 0) + return gposKern; + } + + // Fallback to kern table (legacy) + if (_legacyProvider != null) + { + return _legacyProvider.GetKerning(leftGlyph, rightGlyph); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/LegacyKerningProvider.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/LegacyKerningProvider.cs new file mode 100644 index 0000000000..eba2b218e8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Kerning/LegacyKerningProvider.cs @@ -0,0 +1,85 @@ +using EPPlus.Fonts.OpenType.Tables.Kern; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Kerning +{ + /// + /// Provides kerning from legacy 'kern' table (pre-OpenType). + /// Used as fallback when GPOS is not available. + /// + internal class LegacyKerningProvider + { + private readonly Dictionary _kerningPairs; + + public LegacyKerningProvider(KernTable kernTable) + { + _kerningPairs = BuildKerningDictionary(kernTable); + } + + /// + /// Gets kerning adjustment for a glyph pair from kern table. + /// O(1) lookup via pre-built dictionary. + /// + public short GetKerning(ushort leftGlyph, ushort rightGlyph) + { + ulong key = MakeKey(leftGlyph, rightGlyph); + + if (_kerningPairs.TryGetValue(key, out short value)) + return value; + + return 0; + } + + /// + /// Builds a dictionary of all kerning pairs from the kern table. + /// Called once during construction. + /// + private Dictionary BuildKerningDictionary(KernTable kernTable) + { + var pairs = new Dictionary(); + + if (kernTable?.SubTables == null) + return pairs; + + foreach (var subtable in kernTable.SubTables) + { + // Only support Format 0 (horizontal kerning) + if (subtable.coverage.Format == 0 && subtable.Format0Subtable != null) + { + AddPairsFromFormat0(pairs, subtable.Format0Subtable); + } + } + + return pairs; + } + + /// + /// Adds all kerning pairs from a Format 0 subtable to the dictionary. + /// + private void AddPairsFromFormat0( + Dictionary pairs, + KernSubTableFormat0 format0) + { + if (format0.Pairs == null) + return; + + foreach (var pair in format0.Pairs) + { + ulong key = MakeKey(pair.left, pair.right); + + // Last value wins if duplicate keys + // (matches original behavior of returning first non-zero) + if (pair.value != 0) + { + pairs[key] = pair.value; + } + } + } + + private static ulong MakeKey(ushort leftGlyph, ushort rightGlyph) + { + // Combine two ushorts into one ulong for fast dictionary lookup + return ((ulong)leftGlyph << 16) | rightGlyph; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Ligatures/LigatureProcessor.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Ligatures/LigatureProcessor.cs new file mode 100644 index 0000000000..9ad8d344b8 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Ligatures/LigatureProcessor.cs @@ -0,0 +1,204 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Common.Layout.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Fonts.OpenType.TextShaping.Ligatures +{ + internal class LigatureProcessor + { + private readonly List _ligaLookups; + + public LigatureProcessor(OpenTypeFont font) + { + _font = font; + if (font.GsubTable != null) + { + _ligaLookups = FindLookupsForFeature(font.GsubTable, "liga"); + } + else + { + _ligaLookups = new List(); + } + } + + private readonly OpenTypeFont _font; + + /// + /// Applies standard ligature substitutions (fi, ff, ffi, ffl, etc.). + /// Processes glyphs left-to-right, replacing sequences with ligature glyphs. + /// + internal List ApplyLigatures(List glyphs) + { + var gsub = _font.GsubTable; + if (gsub == null) + return glyphs; + + // Find "liga" feature + var ligaLookups = FindLookupsForFeature(gsub, "liga"); + if (ligaLookups.Count == 0) + return glyphs; + + // Apply each lookup in order + foreach (var lookup in ligaLookups) + { + ApplyLigaturesInPlace(glyphs); + } + + return glyphs; + } + + internal void ApplyLigaturesInPlace(List glyphs) + { + if (_ligaLookups.Count == 0) return; + + foreach (var lookup in _ligaLookups) + { + if (lookup.LookupType != 4) continue; + + int i = 0; + while (i < glyphs.Count) + { + bool substituted = false; + + foreach (var subtableObj in lookup.SubTables) + { + if (subtableObj is not LigatureSubstSubTable subtable) continue; + + if (TryApplyLigatureInPlace(glyphs, i, subtable, out int consumed)) + { + substituted = true; + i += consumed; // Oftast 1 efter ersättning + break; // Första match vinner – hoppa ur + } + } + + if (!substituted) i++; + } + } + } + + private bool TryApplyLigatureInPlace( + List glyphs, + int startIndex, + LigatureSubstSubTable subtable, + out int componentsConsumed) + { + componentsConsumed = 0; + + if (startIndex >= glyphs.Count) return false; + + ushort first = glyphs[startIndex].GlyphId; + int covIdx = subtable.Coverage.GetGlyphIndex(first); + if (covIdx < 0) return false; + + if (!subtable.LigatureSets.TryGetValue(first, out var ligSet) || ligSet?.Ligatures.Count == 0) + return false; + + // Försök längre ligaturer först (rekommenderas av OpenType-spec) + var sortedLigs = ligSet.Ligatures + .OrderByDescending(l => 1 + (l.Components?.Length ?? 0)) + .ToList(); + + foreach (var lig in sortedLigs) + { + int compCount = 1 + (lig.Components?.Length ?? 0); + if (startIndex + compCount > glyphs.Count) continue; + + bool match = true; + for (int j = 0; j < lig.Components?.Length; j++) + { + if (glyphs[startIndex + 1 + j].GlyphId != lig.Components[j]) + { + match = false; + break; + } + } + + if (match) + { + var ligGlyph = CreateLigatureGlyph(glyphs, startIndex, (byte)compCount, lig.LigatureGlyph); + + // MUTERA DIREKT + glyphs.RemoveRange(startIndex, compCount); + glyphs.Insert(startIndex, ligGlyph); + + componentsConsumed = 1; // ligatur tar platsen → nästa steg flyttar förbi den + return true; + } + } + + return false; + } + + + /// + /// Finds all lookups associated with a feature tag. + /// + private List FindLookupsForFeature(GsubTable gsub, string featureTag) + { + var lookups = new List(); + + if (gsub?.FeatureList?.FeatureRecords == null) + return lookups; + + foreach (var featureRecord in gsub.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == featureTag) + { + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < gsub.LookupList.Lookups.Count) + { + lookups.Add(gsub.LookupList.Lookups[lookupIndex]); + } + } + } + } + + return lookups; + } + + + /// + /// Creates a new shaped glyph for a ligature, combining metrics from components. + /// + private ShapedGlyph CreateLigatureGlyph( + List glyphs, + int startIndex, + byte componentCount, + ushort ligatureGlyphId) + { + var baseAdvance = (short)_font.HmtxTable.GetAdvanceWidth(ligatureGlyphId); + var clusterIndex = glyphs[startIndex].ClusterIndex; + + return new ShapedGlyph + { + GlyphId = ligatureGlyphId, + BaseAdvance = baseAdvance, // ← Base advance for ligature + XAdvance = baseAdvance, // ← Will be adjusted by positioning + YAdvance = 0, + XOffset = 0, + YOffset = 0, + ClusterIndex = clusterIndex, + CharCount = componentCount + }; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/MultiLineMetrics.cs b/src/EPPlus.Fonts.OpenType/TextShaping/MultiLineMetrics.cs new file mode 100644 index 0000000000..73b5440624 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/MultiLineMetrics.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ + +namespace EPPlus.Fonts.OpenType.TextShaping +{ + /// + /// Metrics for multi-line text measurement + /// + public struct MultiLineMetrics + { + /// + /// Maximum width of all lines + /// + public float Width { get; set; } + + /// + /// Total height (line count × line height) + /// + public float Height { get; set; } + + /// + /// Font height without line spacing (ascent + descent) + /// + public float FontHeight { get; set; } + + /// + /// Number of lines + /// + public int LineCount { get; set; } + + /// + /// Height of a single line (ascent + descent + line gap) + /// + public float LineHeight { get; set; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/MarkToBaseProvider.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/MarkToBaseProvider.cs new file mode 100644 index 0000000000..1e6c6568f3 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/MarkToBaseProvider.cs @@ -0,0 +1,161 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/20/2025 EPPlus Software AB Mark-to-Base positioning + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType4; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Positioning +{ + /// + /// Provides mark-to-base attachment positioning (GPOS Type 4). + /// Positions combining marks (accents, diacritics) relative to base glyphs. + /// Critical for decomposed Unicode text (e.g., e + ´ → é). + /// + internal class MarkToBaseProvider + { + private readonly List _subtables; + + public MarkToBaseProvider(OpenTypeFont font) + { + if (font.GposTable != null) + { + _subtables = FindAllMarkToBaseSubtables(font.GposTable); + } + else + { + _subtables = new List(); + } + } + + /// + /// Applies mark-to-base positioning to a glyph sequence. + /// Marks are positioned relative to the preceding base glyph. + /// + /// List of shaped glyphs to process + public void ApplyMarkPositioning(List glyphs) + { + if (_subtables.Count == 0 || glyphs.Count < 2) + return; + + // Process glyphs left-to-right + for (int i = 1; i < glyphs.Count; i++) + { + var baseGlyph = glyphs[i - 1]; + var markGlyph = glyphs[i]; + + bool positioned = false; + + // Try each subtable until we find positioning + foreach (var subtable in _subtables) + { + if (TryPositionMark(subtable, baseGlyph, markGlyph)) + { + positioned = true; + break; + } + } + } + } + + /// + /// Attempts to position a mark glyph relative to a base glyph. + /// + private bool TryPositionMark( + MarkToBaseSubTableFormat1 subtable, + ShapedGlyph baseGlyph, + ShapedGlyph markGlyph) + { + // Check if base glyph is in base coverage + int baseIndex = subtable.BaseCoverage?.GetGlyphIndex(baseGlyph.GlyphId) ?? -1; + if (baseIndex < 0 || baseIndex >= subtable.BaseArray.BaseCount) + return false; + + // Check if mark glyph is in mark coverage + int markIndex = subtable.MarkCoverage?.GetGlyphIndex(markGlyph.GlyphId) ?? -1; + if (markIndex < 0 || markIndex >= subtable.MarkArray.MarkCount) + return false; + + // Get mark record (contains class and anchor) + var markRecord = subtable.MarkArray.Records[markIndex]; + ushort markClass = markRecord.MarkClass; + + // Validate mark class + if (markClass >= subtable.MarkClassCount) + return false; + + // Get base record (contains anchors for each mark class) + var baseRecord = subtable.BaseArray.Records[baseIndex]; + if (baseRecord.BaseAnchors == null || markClass >= baseRecord.BaseAnchors.Length) + return false; + + var baseAnchor = baseRecord.BaseAnchors[markClass]; + var markAnchor = markRecord.MarkAnchor; + + if (baseAnchor == null || markAnchor == null) + return false; + + // Calculate mark position relative to base + // Mark is positioned so its anchor aligns with base anchor + var xOffset = baseAnchor.XCoordinate - markAnchor.XCoordinate; + var yOffset = baseAnchor.YCoordinate - markAnchor.YCoordinate; + + // Apply positioning to mark glyph + markGlyph.XOffset = (short)xOffset; + markGlyph.YOffset = (short)yOffset; + + // Mark should not advance (it's positioned over base) + markGlyph.XAdvance = 0; + markGlyph.YAdvance = 0; + + return true; + } + + /// + /// Finds all Mark-to-Base subtables in the "mark" feature. + /// + private List FindAllMarkToBaseSubtables(GposTable gpos) + { + var subtables = new List(); + if (gpos == null) + return subtables; + + foreach (var featureRecord in gpos.FeatureList.FeatureRecords) + { + if (featureRecord.FeatureTag.Value == "mark") + { + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex >= gpos.LookupList.Lookups.Count) + continue; + + var lookup = gpos.LookupList.Lookups[lookupIndex]; + + // ✅ Kolla bara innehållet, ignorera LookupType + foreach (var subtable in lookup.SubTables) + { + if (subtable is MarkToBaseSubTableFormat1 markToBase) + { + subtables.Add(markToBase); + } + } + } + } + } + + return subtables; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/SingleAdjustmentProvider.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/SingleAdjustmentProvider.cs new file mode 100644 index 0000000000..3e3f37fdc7 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Positioning/SingleAdjustmentProvider.cs @@ -0,0 +1,125 @@ +using EPPlus.Fonts.OpenType.Tables.Gpos; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups; +using EPPlus.Fonts.OpenType.Tables.Gpos.Data.Lookups.LookupType1; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Positioning +{ + /// + /// Provides single glyph positioning adjustments from GPOS Lookup Type 1. + /// Handles both Format 1 (uniform adjustment) and Format 2 (per-glyph adjustments). + /// + internal class SingleAdjustmentProvider + { + private readonly OpenTypeFont _font; + private readonly Dictionary> _subtablesByFeature; + + public SingleAdjustmentProvider(OpenTypeFont font) + { + _font = font; + _subtablesByFeature = new Dictionary>(); + + if (font?.GposTable != null) + { + BuildFeatureMap(font.GposTable); + } + } + + /// + /// Tries to get positioning adjustment for a single glyph using specified features. + /// + /// The glyph ID to look up + /// List of feature tags to search (e.g., ["kern"]) + /// The ValueRecord if found + /// True if an adjustment was found + public bool TryGetAdjustment(ushort glyphId, List features, out ValueRecord value) + { + if (features == null || features.Count == 0) + { + // No features specified - don't apply any single adjustments + value = null; + return false; + } + + // Search in specified features + foreach (var feature in features) + { + if (_subtablesByFeature.TryGetValue(feature, out var subtables)) + { + foreach (var subtable in subtables) + { + if (TryGetAdjustmentFromSubtable(subtable, glyphId, out value)) + { + return true; + } + } + } + } + + value = null; + return false; + } + + private bool TryGetAdjustmentFromSubtable(GposSubTableBase subtable, ushort glyphId, out ValueRecord value) + { + // Try Format 1 + if (subtable is SinglePosSubTableFormat1 format1) + { + return format1.TryGetAdjustment(glyphId, out value); + } + // Try Format 2 + else if (subtable is SinglePosSubTableFormat2 format2) + { + return format2.TryGetAdjustment(glyphId, out value); + } + + value = null; + return false; + } + + /// + /// Builds a map of feature tags to their Single Adjustment subtables. + /// + private void BuildFeatureMap(GposTable gpos) + { + if (gpos?.FeatureList == null || gpos.LookupList == null) + return; + + foreach (var featureRecord in gpos.FeatureList.FeatureRecords) + { + string featureTag = featureRecord.FeatureTag.Value; + var feature = featureRecord.FeatureTable; + + if (feature?.LookupListIndices == null) + continue; + + var subtables = new List(); + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex >= gpos.LookupList.Lookups.Count) + continue; + + var lookup = gpos.LookupList.Lookups[lookupIndex]; + + // We want Single Adjustment (Type 1) + if (lookup.LookupType == 1 && lookup.SubTables != null) + { + foreach (var subtable in lookup.SubTables) + { + if (subtable is SinglePosSubTableFormat1 || subtable is SinglePosSubTableFormat2) + { + subtables.Add((GposSubTableBase)subtable); + } + } + } + } + + if (subtables.Count > 0) + { + _subtablesByFeature[featureTag] = subtables; + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/Substitutions/SingleSubstitutionProcessor.cs b/src/EPPlus.Fonts.OpenType/TextShaping/Substitutions/SingleSubstitutionProcessor.cs new file mode 100644 index 0000000000..b3ba88a383 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/Substitutions/SingleSubstitutionProcessor.cs @@ -0,0 +1,166 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/19/2026 EPPlus Software AB GSUB Single Substitution support + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables.Gsub; +using EPPlus.Fonts.OpenType.Tables.Gsub.Data.Lookups; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping.Substitutions +{ + /// + /// Processes GSUB Lookup Type 1 (Single Substitution). + /// This handles 1:1 glyph replacements like small caps, oldstyle figures, etc. + /// + internal class SingleSubstitutionProcessor + { + private readonly OpenTypeFont _font; + private readonly GsubTable _gsubTable; + private readonly Dictionary> _featureSubtables; + + public SingleSubstitutionProcessor(OpenTypeFont font) + { + _font = font; + _gsubTable = font?.GsubTable; + _featureSubtables = new Dictionary>(); + + if (_gsubTable != null) + { + BuildFeatureSubtableMap(); + } + } + + /// + /// Applies single substitution to the glyph list. + /// This processes all glyphs and replaces them according to the active features. + /// + /// List of shaped glyphs to process + /// List of feature tags to apply (e.g., "smcp", "onum") + /// Modified glyph list with substitutions applied + public List ApplySubstitutions(List glyphs, List activeFeatures) + { + if (glyphs == null || glyphs.Count == 0) + return glyphs; + + if (activeFeatures == null || activeFeatures.Count == 0) + return glyphs; + + // Collect all subtables for the active features + var subtablesToApply = new List(); + foreach (var feature in activeFeatures) + { + if (_featureSubtables.TryGetValue(feature, out var subtables)) + { + subtablesToApply.AddRange(subtables); + } + } + + if (subtablesToApply.Count == 0) + return glyphs; + + // Process each glyph + for (int i = 0; i < glyphs.Count; i++) + { + ushort originalGlyphId = glyphs[i].GlyphId; + + // Try to find a substitution for this glyph in the active subtables + if (TryGetSubstitution(originalGlyphId, subtablesToApply, out ushort newGlyphId)) + { + // ✅ FIX: Update both GlyphId AND BaseAdvance for the new glyph + var glyph = glyphs[i]; + glyph.GlyphId = newGlyphId; + + // Get the new glyph's advance width from hmtx + var newAdvance = (short)_font.HmtxTable.GetAdvanceWidth(newGlyphId); + glyph.BaseAdvance = newAdvance; // ✅ Update base advance + glyph.XAdvance = newAdvance; // ✅ Reset to base (kerning will be reapplied) + + glyphs[i] = glyph; + } + } + + return glyphs; + } + + /// + /// Tries to find a substitution for a given glyph ID in the specified subtables. + /// + private bool TryGetSubstitution(ushort glyphId, List subtables, out ushort substitutedGlyphId) + { + substitutedGlyphId = glyphId; // Default to no change + + foreach (var subtable in subtables) + { + // Check if this glyph is covered by this subtable + int coverageIndex = subtable.Coverage?.GetGlyphIndex(glyphId) ?? -1; + + if (coverageIndex >= 0) + { + // Glyph is covered, get the substitution + ushort result = subtable.GetSubstitution(glyphId); + + // Even if result is 0, it's a valid substitution (could be .notdef) + // Only skip if it's the same as input (no actual change) + if (result != glyphId) + { + substitutedGlyphId = result; + return true; + } + } + } + + return false; // No substitution found in any subtable + } + + /// + /// Builds a map of feature tags to their Single Substitution subtables. + /// This allows us to only apply substitutions for active features. + /// + private void BuildFeatureSubtableMap() + { + if (_gsubTable?.FeatureList?.FeatureRecords == null) + return; + + foreach (var featureRecord in _gsubTable.FeatureList.FeatureRecords) + { + string featureTag = featureRecord.FeatureTag.Value; + + if (!_featureSubtables.ContainsKey(featureTag)) + { + _featureSubtables[featureTag] = new List(); + } + + var feature = featureRecord.FeatureTable; + + foreach (var lookupIndex in feature.LookupListIndices) + { + if (lookupIndex < _gsubTable.LookupList.Lookups.Count) + { + var lookup = _gsubTable.LookupList.Lookups[lookupIndex]; + + // Only process Type 1 (Single Substitution) lookups + if (lookup.LookupType == 1) + { + foreach (var subtable in lookup.SubTables) + { + if (subtable is SingleSubstSubTable singleSubst) + { + _featureSubtables[featureTag].Add(singleSubst); + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.Vertical.cs b/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.Vertical.cs new file mode 100644 index 0000000000..aa0b166f61 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.Vertical.cs @@ -0,0 +1,178 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical text shaping support (Excel rotation 255) + Requires TextShaper.cs to be declared as partial + *************************************************************************************************/ +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping +{ + public partial class TextShaper + { + #region Vertical Text Shaping (Excel text rotation value 255) + + /// + /// Shapes text for vertical layout (top-to-bottom glyph stacking). + /// Used for Excel vertical text mode (text rotation value 255). + /// No GSUB or GPOS is applied - the pipeline is intentionally minimal: + /// character mapping + vertical metrics lookup only. + /// + /// Text to shape + /// Shaping options (reserved for future use) + /// Shaped vertical text with positioned glyphs in font design units + public ShapedVerticalText ShapeVertical(string text, ShapingOptions options = null) + { + if (string.IsNullOrEmpty(text)) + { + return new ShapedVerticalText + { + OriginalText = text ?? string.Empty, + Glyphs = new VerticalShapedGlyph[0] + }; + } + + var glyphs = MapToVerticalGlyphs(text); + + return new ShapedVerticalText + { + OriginalText = text, + Glyphs = glyphs.ToArray() + }; + } + + /// + /// Shapes text for vertical layout into lightweight VerticalGlyphHeight structs + /// optimized for vertical text measurement. + /// Analogous to ShapeLight() for horizontal text. + /// + /// Text to shape + /// Shaping options (reserved for future use) + /// Array of lightweight vertical glyph height structs (8 bytes each) + public VerticalGlyphHeight[] ShapeLightVertical(string text, ShapingOptions options = null) + { + if (string.IsNullOrEmpty(text)) + { + return new VerticalGlyphHeight[0]; + } + + var glyphs = MapToVerticalGlyphs(text); + return ExtractVerticalGlyphHeights(glyphs); + } + + /// + /// Maps characters to vertical glyphs, resolving advance heights from vmtx. + /// Falls back to hmtx advance widths for fonts without vertical metrics. + /// Handles surrogate pairs for supplementary plane characters. + /// + private List MapToVerticalGlyphs(string text) + { + var glyphs = new List(text.Length); + + int i = 0; + while (i < text.Length) + { + uint codePoint; + int charCount; + + if (i < text.Length - 1 && char.IsHighSurrogate(text[i]) && char.IsLowSurrogate(text[i + 1])) + { + codePoint = (uint)char.ConvertToUtf32(text[i], text[i + 1]); + charCount = 2; + } + else if (char.IsSurrogate(text[i])) + { + // Lone surrogate - map to .notdef + codePoint = 0; + charCount = 1; + } + else + { + codePoint = text[i]; + charCount = 1; + } + + // Resolve glyph via font provider (with fallback support) + OpenTypeFont font; + ushort glyphId; + _fontProvider.TryGetGlyphFont(codePoint, out font, out glyphId); + + byte fontId = GetOrRegisterFontId(font); + + ushort advanceHeight; + short topSideBearing; + GetVerticalMetrics(font, glyphId, out advanceHeight, out topSideBearing); + // Fetch horizontal advance width for centering + ushort advanceWidth = font.HmtxTable.GetAdvanceWidth(glyphId); + + glyphs.Add(new VerticalShapedGlyph( + glyphId, + advanceHeight, + topSideBearing, + advanceWidth, + (ushort)i, + (byte)charCount, + fontId + )); + + i += charCount; + } + + return glyphs; + } + + /// + /// Extracts VerticalGlyphHeight structs from a list of VerticalShapedGlyphs. + /// Discards TopSideBearing as it is not needed for height measurement. + /// + private VerticalGlyphHeight[] ExtractVerticalGlyphHeights(List glyphs) + { + var result = new VerticalGlyphHeight[glyphs.Count]; + for (int i = 0; i < glyphs.Count; i++) + { + var g = glyphs[i]; + result[i] = new VerticalGlyphHeight + { + YAdvance = g.YAdvance, + ClusterIndex = g.ClusterIndex, + CharCount = g.CharCount + }; + } + return result; + } + + /// + /// Resolves vertical metrics for a glyph from the given font. + /// Uses vmtx (advanceHeight + topSideBearing) when available. + /// Falls back to hmtx advanceWidth as advanceHeight when vmtx is absent, + /// with topSideBearing set to 0. + /// + private void GetVerticalMetrics(OpenTypeFont font, ushort glyphId, + out ushort advanceHeight, out short topSideBearing) + { + var vmtx = font.VmtxTable; + if (vmtx != null) + { + advanceHeight = vmtx.GetAdvanceHeight(glyphId); + topSideBearing = vmtx.GetTopSideBearing(glyphId); + } + else + { + // Fallback: use horizontal advance width as advance height. + // Gives reasonable glyph spacing for fonts without vertical metrics. + advanceHeight = font.HmtxTable.GetAdvanceWidth(glyphId); + topSideBearing = 0; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.cs b/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.cs new file mode 100644 index 0000000000..3af30c604e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/TextShaping/TextShaper.cs @@ -0,0 +1,876 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + 01/19/2026 EPPlus Software AB Added Single Adjustment support (GPOS Type 1) + 02/05/2026 EPPlus Software AB Added IFontProvider support for fallback fonts + 03/20/2026 EPPlus Software AB ResetFontTracking made private, called automatically + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.TextShaping.Contextual; +using EPPlus.Fonts.OpenType.TextShaping.Kerning; +using EPPlus.Fonts.OpenType.TextShaping.Ligatures; +using EPPlus.Fonts.OpenType.TextShaping.Positioning; +using EPPlus.Fonts.OpenType.TextShaping.Substitutions; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Interfaces.RichText; +using System; +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.TextShaping +{ + public partial class TextShaper : ITextShaper + { + private readonly OpenTypeFont _primaryFont; + private readonly KerningProvider _kerningProvider; + private readonly LigatureProcessor _ligatureProcessor; + private readonly MarkToBaseProvider _markToBaseProvider; + private readonly SingleAdjustmentProvider _singleAdjustmentProvider; + private readonly SingleSubstitutionProcessor _singleSubstitutionProcessor; + private readonly ChainingContextualProcessor _chainingContextualProcessor; + private readonly IFontProvider _fontProvider; + + // Font tracking for multi-font support + private readonly Dictionary _fontToIdMap = new Dictionary(); + private readonly List _usedFonts = new List(); + + private const ushort DEFAULT_UNITS_PER_EM = 1000; + + public ushort UnitsPerEm + { + get + { + if (_primaryFont?.HeadTable?.UnitsPerEm == null || _primaryFont.HeadTable.UnitsPerEm == 0) + { + return DEFAULT_UNITS_PER_EM; + } + return _primaryFont.HeadTable.UnitsPerEm; + } + } + + /// + /// Creates a TextShaper with automatic emoji fallback (DefaultFontProvider). + /// NOTE: In most cases, prefer OpenTypeFonts.GetTextShaper() over creating + /// instances directly. It provides a thread-local cached instance and avoids + /// duplicate caches across the codebase. + /// + public TextShaper(OpenTypeFontEngine engine, OpenTypeFont font) + : this(new DefaultFontProvider(engine, font)) { } + + /// + /// Creates a TextShaper with custom font provider. + /// NOTE: In most cases, prefer OpenTypeFonts.GetTextShaper() over creating + /// instances directly. It provides a thread-local cached instance and avoids + /// duplicate caches across the codebase. + /// + public TextShaper(IFontProvider fontProvider) + { + if (fontProvider == null) + throw new ArgumentNullException("fontProvider"); + if (fontProvider.PrimaryFont == null) + throw new ArgumentException("Primary font cannot be null in font provider", "fontProvider"); + + var gposTable = fontProvider.PrimaryFont.GposTable; // Force load now - thread-safe via TableLoader + + _fontProvider = fontProvider; + _primaryFont = fontProvider.PrimaryFont; + + // Initialize processors with primary font + _kerningProvider = new KerningProvider(_primaryFont); + _ligatureProcessor = new LigatureProcessor(_primaryFont); + _markToBaseProvider = new MarkToBaseProvider(_primaryFont); + _singleAdjustmentProvider = new SingleAdjustmentProvider(_primaryFont); + _singleSubstitutionProcessor = new SingleSubstitutionProcessor(_primaryFont); + _chainingContextualProcessor = new ChainingContextualProcessor(_primaryFont, _singleSubstitutionProcessor, _ligatureProcessor); + } + + /// + /// Resolves a shaper for a different font via this shaper's font provider. Returns null + /// when the provider is not engine-backed (e.g. a custom IFontProvider), in which case the + /// caller is expected to fall back. This lets a TextLayoutEngine shape multi-font rich text + /// through the engine that produced this shaper instead of the global singleton. + /// + internal ITextShaper GetShaperForFont(IFontFormatBase font) + { + var dfp = _fontProvider as DefaultFontProvider; + if (dfp != null) + return dfp.GetShaperForFont(font); + + return null; + } + + internal ITextShaper GetShaperForFont(MeasurementFont font) + { + var dfp = _fontProvider as DefaultFontProvider; + if (dfp != null) + return dfp.GetShaperForFont(font); + + return null; + } + + #region Font Tracking API + + /// + /// Gets all fonts used in the last shaping operation. + /// Used for subsetting and PDF embedding when text uses multiple fonts. + /// + public IEnumerable GetUsedFonts() + { + return _usedFonts; + } + + /// + /// Resets font tracking state. Called automatically at the start of each + /// shaping operation — Shape(), ExtractCharWidths(), ShapeLight(). + /// + /// The primary font is registered immediately with FontId 0, regardless of + /// whether it ends up contributing any glyphs. This preserves the invariant + /// that FontId 0 always refers to the primary font — without it, a string that + /// uses only fallback glyphs (e.g. pure CJK text against a Latin primary) would + /// leave the primary out of _usedFonts entirely, and the first fallback would + /// end up with FontId 0. + /// + private void ResetFontTracking() + { + _usedFonts.Clear(); + _fontToIdMap.Clear(); + + // Reserve FontId 0 for the primary font, even before any glyphs are mapped. + _usedFonts.Add(_primaryFont); + _fontToIdMap[_primaryFont] = 0; + } + + /// + /// Gets or registers a font ID for tracking. + /// Returns: 0 for primary font, 1+ for fallback fonts. + /// + private byte GetOrRegisterFontId(OpenTypeFont font) + { + byte fontId; + if (_fontToIdMap.TryGetValue(font, out fontId)) + { + return fontId; + } + + fontId = (byte)_usedFonts.Count; + _usedFonts.Add(font); + _fontToIdMap[font] = fontId; + return fontId; + } + + #endregion + + #region Single-line Shaping + + /// + /// Shape text using default options (ligatures + kerning). + /// + /// Text to shape + /// Shaped text with positioned glyphs + public ShapedText Shape(string text) + { + return Shape(text, ShapingOptions.Default); + } + + /// + /// Shape text with specified options. + /// Note: Newline characters (\n, \r, \r\n) are treated as regular characters. + /// For multi-line text, use ShapeLines() method instead. + /// + /// Text to shape + /// Shaping options + /// Shaped text with positioned glyphs + public ShapedText Shape(string text, ShapingOptions options) + { + ResetFontTracking(); + + if (string.IsNullOrEmpty(text)) + { + return new ShapedText + { + OriginalText = text ?? string.Empty, + Glyphs = new ShapedGlyph[0] + }; + } + + if (options == null) + { + options = ShapingOptions.Default; + } + + // Phase 1: Map characters to glyphs (with font fallback support) + var glyphs = MapToGlyphs(text); + + // Phase 2: Apply GSUB substitutions (if enabled) - ONLY on primary font glyphs + if (options.ApplySubstitutions && _primaryFont.GsubTable != null) + { + glyphs = ApplyGsubSubstitutions(glyphs, options); + } + + // Phase 3: Apply GPOS positioning (if enabled) - ONLY on primary font glyphs + if (options.ApplyPositioning) + { + ApplyPositioning(glyphs, options); + } + + // Phase 4: Build result + var fontUnitsPerEm = BuildFontUnitsPerEm(); + var fontLineHeights = BuildFontLineHeights(); + return new ShapedText + { + OriginalText = text, + Glyphs = glyphs.ToArray(), + FontUnitsPerEm = fontUnitsPerEm, + FontLineHeights = fontLineHeights + }; + } + + /// + /// Extracts character widths and returns a new array. + /// For repeated calls, consider using ExtractCharWidths(text, fontSize, options, targetArray) + /// to avoid allocations. + /// + public double[] ExtractCharWidths(string text, float fontSize, ShapingOptions options) + { + var charWidths = new double[text.Length]; + + if (string.IsNullOrEmpty(text)) + { + return charWidths; + } + + ExtractCharWidthsCore(text, fontSize, options, charWidths); + return charWidths; + } + + /// + /// Extracts character widths into a pre-allocated target array to avoid new allocations. + /// Writes widths for the first text.Length positions; caller must ensure targetArray.Length >= text.Length. + /// + /// The text to measure + /// Font size in points + /// Shaping options + /// Pre-allocated array to write widths into (must be large enough) + public void ExtractCharWidths(string text, float fontSize, ShapingOptions options, double[] targetArray) + { + if (string.IsNullOrEmpty(text)) + { + return; + } + + if (targetArray == null || targetArray.Length < text.Length) + { + throw new ArgumentException( + string.Format("Target array must be at least as large as text length ({0})", text.Length), + "targetArray"); + } + + ExtractCharWidthsCore(text, fontSize, options, targetArray); + } + + /// + /// Core implementation that extracts char widths into provided buffer. + /// OPTIMIZED: Avoids creating ShapedText object and copying glyphs to array. + /// Works directly with List<ShapedGlyph> for better memory efficiency. + /// + private void ExtractCharWidthsCore(string text, float fontSize, ShapingOptions options, double[] targetArray) + { + ResetFontTracking(); + + // Clear only the portion we will use + Array.Clear(targetArray, 0, text.Length); + + // Phase 1: Map characters to glyphs + var glyphs = MapToGlyphs(text); + + // Phase 2: Apply GSUB substitutions (if enabled) + if (options.ApplySubstitutions && _primaryFont.GsubTable != null) + { + glyphs = ApplyGsubSubstitutions(glyphs, options); + } + + // Phase 3: Apply GPOS positioning (if enabled) + if (options.ApplyPositioning) + { + ApplyPositioning(glyphs, options); + } + + // Phase 4: Extract widths - must handle multi-font glyphs + foreach (var glyph in glyphs) + { + int charIndex = glyph.ClusterIndex; + if (charIndex >= 0 && charIndex < text.Length) + { + // Get the font for this glyph + OpenTypeFont font = _usedFonts[glyph.FontId]; + double scaleFactor = fontSize / font.HeadTable.UnitsPerEm; + + targetArray[charIndex] += glyph.XAdvance * scaleFactor; + } + } + } + + #endregion + + #region Phase 1: Character to Glyph Mapping + + /// + /// Maps characters to glyphs using the cmap table. + /// CORRECTLY handles surrogate pairs for emoji and supplementary plane characters. + /// Supports multi-font fallback via IFontProvider. + /// + private List MapToGlyphs(string text) + { + var glyphs = new List(text.Length); + + int i = 0; + while (i < text.Length) + { + uint codePoint; + int charCount; + + // Check if this is a surrogate pair + if (i < text.Length - 1 && char.IsHighSurrogate(text[i])) + { + // Potential surrogate pair: 2 chars → 1 Unicode code point + char high = text[i]; + char low = text[i + 1]; + + if (char.IsLowSurrogate(low)) + { + // Valid pair - convert to code point + codePoint = (uint)char.ConvertToUtf32(high, low); + charCount = 2; + } + else + { + // Invalid surrogate pair - treat as .notdef and skip high surrogate + codePoint = 0; + charCount = 1; + } + } + else if (char.IsSurrogate(text[i])) + { + // Lone surrogate (invalid) - treat as .notdef + codePoint = 0; + charCount = 1; + } + else + { + // Normal BMP character + codePoint = text[i]; + charCount = 1; + } + + // Use font provider to find glyph (with fallback support) + OpenTypeFont font; + ushort glyphId; + _fontProvider.TryGetGlyphFont(codePoint, out font, out glyphId); + + // Get font ID for multi-font tracking + byte fontId = GetOrRegisterFontId(font); + + // Get advance width from the font that contains this glyph + var hmtxTable = font.HmtxTable; + var baseAdvance = (short)hmtxTable.GetAdvanceWidth(glyphId); + + glyphs.Add(new ShapedGlyph + { + GlyphId = glyphId, + BaseAdvance = baseAdvance, + XAdvance = baseAdvance, + YAdvance = 0, + XOffset = 0, + YOffset = 0, + ClusterIndex = (ushort)i, + CharCount = (byte)charCount, + FontId = fontId // Track which font this glyph comes from + }); + + i += charCount; + } + + return glyphs; + } + + #endregion + + #region Phase 2: GSUB Substitutions + + /// + /// Applies GSUB substitutions (ligatures, contextual alternates, etc.). + /// IMPORTANT: Only processes glyphs from primary font (FontId == 0). + /// Fallback font glyphs are not affected by substitutions. + /// + private List ApplyGsubSubstitutions(List glyphs, ShapingOptions options) + { + // Quick check: If all glyphs are from primary font, process directly + bool hasNonPrimaryGlyphs = false; + foreach (var g in glyphs) + { + if (g.FontId != 0) + { + hasNonPrimaryGlyphs = true; + break; + } + } + + if (!hasNonPrimaryGlyphs) + { + // All glyphs are primary - process directly (optimization) + glyphs = ApplyGsubSubstitutionsInternal(glyphs, options); + return glyphs; + } + + // Mixed fonts: Extract primary glyphs, process, then merge back + var primaryGlyphs = new List(); + var primaryIndices = new List(); + + for (int i = 0; i < glyphs.Count; i++) + { + if (glyphs[i].FontId == 0) + { + primaryGlyphs.Add(glyphs[i]); + primaryIndices.Add(i); + } + } + + if (primaryGlyphs.Count == 0) + { + return glyphs; // No primary font glyphs to process + } + + // Process primary glyphs + primaryGlyphs = ApplyGsubSubstitutionsInternal(primaryGlyphs, options); + + // Merge back: Replace primary glyphs in original list + var result = new List(glyphs); + + // Remove old primary glyphs (in reverse to maintain indices) + for (int i = primaryIndices.Count - 1; i >= 0; i--) + { + result.RemoveAt(primaryIndices[i]); + } + + // Insert processed primary glyphs at first primary position + int insertPosition = primaryIndices.Count > 0 ? primaryIndices[0] : 0; + result.InsertRange(insertPosition, primaryGlyphs); + + return result; + } + + /// + /// Internal method that applies GSUB substitutions to a list of glyphs. + /// Assumes all glyphs are from the same font. + /// + private List ApplyGsubSubstitutionsInternal(List glyphs, ShapingOptions options) + { + // Phase 1: Single Substitution (Type 1) + if (options.GsubFeatures != null && options.GsubFeatures.Count > 0) + { + glyphs = _singleSubstitutionProcessor.ApplySubstitutions(glyphs, options.GsubFeatures); + } + + // Phase 2: Chaining Contextual Substitution (Type 6) + if (options.GsubFeatures != null && options.GsubFeatures.Contains("liga")) + { + glyphs = _chainingContextualProcessor.ApplyContextualSubstitutions(glyphs, "liga"); + } + + // Phase 3: Simple Ligatures (Type 4) + if (options.GsubFeatures != null && options.GsubFeatures.Contains("liga")) + { + _ligatureProcessor.ApplyLigaturesInPlace(glyphs); + } + + return glyphs; + } + + #endregion + + #region Phase 3: Positioning + + /// + /// Applies positioning adjustments (kerning, mark positioning, etc.). + /// IMPORTANT: Only processes glyphs from primary font (FontId == 0). + /// Order matters: Single adjustments → Kerning → Mark positioning + /// + private void ApplyPositioning(List glyphs, ShapingOptions options) + { + if (!options.ApplyPositioning) + { + return; + } + + bool applyAllFeatures = options.GposFeatures == null || options.GposFeatures.Count == 0; + + // Phase 1: Single Adjustment (GPOS Type 1) - primary font only + ApplySingleAdjustment(glyphs, options); + + // Phase 2: Kerning (GPOS Type 2 / kern table) - primary font only + if (applyAllFeatures || (options.GposFeatures != null && options.GposFeatures.Contains("kern"))) + { + ApplyKerning(glyphs); + } + + // Phase 3: Mark-to-Base positioning (GPOS Type 4) - primary font only + _markToBaseProvider.ApplyMarkPositioning(glyphs); + } + + /// + /// Applies single glyph adjustments from GPOS Lookup Type 1. + /// Only applies to primary font glyphs (FontId == 0). + /// + private void ApplySingleAdjustment(List glyphs, ShapingOptions options) + { + List features = options.GposFeatures ?? new List(); + + for (int i = 0; i < glyphs.Count; i++) + { + // Skip fallback font glyphs + if (glyphs[i].FontId != 0) + continue; + + ushort glyphId = glyphs[i].GlyphId; + + if (_singleAdjustmentProvider.TryGetAdjustment(glyphId, features, out var valueRecord)) + { + var glyph = glyphs[i]; + + if (valueRecord.XPlacement != 0) + glyph.XOffset += valueRecord.XPlacement; + if (valueRecord.YPlacement != 0) + glyph.YOffset += valueRecord.YPlacement; + if (valueRecord.XAdvance != 0) + glyph.XAdvance += valueRecord.XAdvance; + if (valueRecord.YAdvance != 0) + glyph.YAdvance += valueRecord.YAdvance; + + glyphs[i] = glyph; + } + } + } + + /// + /// Applies kerning adjustments to glyph pairs. + /// Only kerns between primary font glyphs (FontId == 0). + /// + private void ApplyKerning(List glyphs) + { + for (int i = 1; i < glyphs.Count; i++) + { + // Only kern if BOTH glyphs are from primary font + if (glyphs[i - 1].FontId != 0 || glyphs[i].FontId != 0) + continue; + + ushort leftGlyph = glyphs[i - 1].GlyphId; + ushort rightGlyph = glyphs[i].GlyphId; + + short kernValue = _kerningProvider.GetKerning(leftGlyph, rightGlyph); + + if (kernValue != 0) + { + var glyph = glyphs[i - 1]; + glyph.XAdvance += kernValue; + glyphs[i - 1] = glyph; + } + } + } + + #endregion + + #region Utilities + + /// + /// Measures the width of text in PDF points. + /// + public float MeasureTextInPoints(string text, float fontSize, ShapingOptions options = null) + { + var shaped = Shape(text, options); + return shaped.GetWidthInPoints(fontSize); + } + + /// + /// Measures the width of text in pixels. + /// + public float MeasureTextInPixels(string text, float fontSize, float dpi, ShapingOptions options = null) + { + var shaped = Shape(text, options); + return shaped.GetWidthInPixels(fontSize, dpi); + } + + #endregion + + #region Multi-line Support + + /// + /// Shape multi-line text (handles \n, \r, \r\n). + /// Returns one ShapedText per line. + /// + public ShapedText[] ShapeLines(string text, ShapingOptions options = null) + { + if (string.IsNullOrEmpty(text)) + { + return new ShapedText[0]; + } + + var lines = text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + var result = new ShapedText[lines.Length]; + + for (int i = 0; i < lines.Length; i++) + { + result[i] = Shape(lines[i], options); + } + + return result; + } + + /// + /// Measure multi-line text and return bounding box. + /// + public MultiLineMetrics MeasureLines(string text, float fontSize, ShapingOptions options = null) + { + var shapedLines = ShapeLines(text, options); + + float maxWidth = 0; + foreach (var line in shapedLines) + { + float lineWidth = line.GetWidthInPoints(fontSize); + maxWidth = Math.Max(maxWidth, lineWidth); + } + + float lineHeight = GetLineHeightInPoints(fontSize); + float fontHeight = GetFontHeightInPoints(fontSize); + float totalHeight = shapedLines.Length * lineHeight; + + return new MultiLineMetrics + { + Width = maxWidth, + Height = totalHeight, + FontHeight = fontHeight, + LineCount = shapedLines.Length, + LineHeight = lineHeight + }; + } + + #endregion + + #region Light Shaping Pipeline + + /// + /// Shapes text into lightweight GlyphWidth structs optimized for text measurement. + /// + public ShapedLightText ShapeLight(string text, ShapingOptions options = null) + { + ResetFontTracking(); + + if (string.IsNullOrEmpty(text)) + { + return new ShapedLightText + { + Glyphs = new GlyphWidth[0], + FontUnitsPerEm = new ushort[] { _primaryFont.HeadTable.UnitsPerEm } + }; + } + + if (options == null) + options = ShapingOptions.Default; + + var glyphs = MapToGlyphs(text); + + if (options.ApplySubstitutions && _primaryFont.GsubTable != null) + { + glyphs = ApplyGsubSubstitutions(glyphs, options); + } + + if (options.ApplyPositioning) + { + ApplyKerningOnly(glyphs); + } + + return new ShapedLightText + { + Glyphs = ExtractGlyphWidths(glyphs), + FontUnitsPerEm = BuildFontUnitsPerEm() + }; + } + + /// + /// Gets the UnitsPerEm for each font used in the last shaping operation. + /// Indexed by FontId. Must be called after Shape/ShapeLight and before ResetFontTracking. + /// + public ushort[] GetFontUnitsPerEm() + { + return BuildFontUnitsPerEm(); + } + + private void ApplyKerningOnly(List glyphs) + { + for (int i = 1; i < glyphs.Count; i++) + { + // Only kern primary font glyphs + if (glyphs[i - 1].FontId != 0 || glyphs[i].FontId != 0) + continue; + + ushort leftGlyph = glyphs[i - 1].GlyphId; + ushort rightGlyph = glyphs[i].GlyphId; + + short kernValue = _kerningProvider.GetKerning(leftGlyph, rightGlyph); + + if (kernValue != 0) + { + var glyph = glyphs[i - 1]; + glyph.XAdvance += kernValue; + glyphs[i - 1] = glyph; + } + } + } + + private GlyphWidth[] ExtractGlyphWidths(List glyphs) + { + var result = new GlyphWidth[glyphs.Count]; + + for (int i = 0; i < glyphs.Count; i++) + { + var g = glyphs[i]; + result[i] = new GlyphWidth + { + XAdvance = (ushort)g.XAdvance, + ClusterIndex = g.ClusterIndex, + CharCount = g.CharCount, + FontId = g.FontId + }; + } + + return result; + } + + #endregion + + #region Font Metrics + + /// + /// Gets single line spacing (baseline-to-baseline distance). + /// + public float GetLineHeightInPoints(float fontSize) + { + if (_primaryFont.Os2Table.UseTypoMetrics) + { + var typoAscent = _primaryFont.Os2Table.sTypoAscender; + var typoDescent = _primaryFont.Os2Table.sTypoDescender; + var typoLineGap = _primaryFont.Os2Table.sTypoLineGap; + float em = _primaryFont.HeadTable.UnitsPerEm; + float lineHeight = typoAscent - typoDescent + typoLineGap; + return (lineHeight / em) * fontSize; + } + else + { + return GetFontHeightInPoints(fontSize); + } + } + + /// + /// Calculates the total height of the font, in points. + /// + public float GetFontHeightInPoints(float fontSize) + { + var ascent = _primaryFont.Os2Table.usWinAscent; + var descent = _primaryFont.Os2Table.usWinDescent; + var em = _primaryFont.HeadTable.UnitsPerEm; + + return (ascent + descent) * (fontSize / em); + } + + /// + /// Calculates the distance from the top of the font's bounding box to the baseline. + /// + /// The font size, in points, for which to calculate the baseline position. Must be a positive value. + /// The distance, in points, from the top of the font's bounding box to the baseline for the given font size. + public float GetAscentInPoints(float fontSize) + { + var ascent = _primaryFont.Os2Table.UseTypoMetrics + ? (float)_primaryFont.Os2Table.sTypoAscender + : _primaryFont.Os2Table.usWinAscent; + + var em = _primaryFont.HeadTable.UnitsPerEm; + return ascent * (fontSize / em); + } + + /// + /// Calculates the font descent in points. + /// + public float GetDescentInPoints(float fontSize) + { + var descent = _primaryFont.Os2Table.UseTypoMetrics + ? (float)Math.Abs(_primaryFont.Os2Table.sTypoDescender) + : _primaryFont.Os2Table.usWinDescent; + + var em = _primaryFont.HeadTable.UnitsPerEm; + return descent * (fontSize / em); + } + + #endregion + + /// + /// Builds a UnitsPerEm lookup array indexed by FontId. + /// Must be called after shaping when _usedFonts is populated. + /// + private ushort[] BuildFontUnitsPerEm() + { + if (_usedFonts.Count == 0) + return new ushort[] { _primaryFont.HeadTable.UnitsPerEm }; + + var result = new ushort[_usedFonts.Count]; + for (int i = 0; i < _usedFonts.Count; i++) + { + result[i] = _usedFonts[i].HeadTable.UnitsPerEm; + } + return result; + } + + /// + /// Builds a line height lookup array (in design units) indexed by FontId. + /// Uses the same metric selection logic as GetLineHeightInPoints: + /// if USE_TYPO_METRICS is set, uses sTypoAscender - sTypoDescender + sTypoLineGap; + /// otherwise uses usWinAscent + usWinDescent. + /// + private int[] BuildFontLineHeights() + { + if (_usedFonts.Count == 0) + return new int[] { GetLineHeightDesignUnits(_primaryFont) }; + + var result = new int[_usedFonts.Count]; + for (int i = 0; i < _usedFonts.Count; i++) + { + result[i] = GetLineHeightDesignUnits(_usedFonts[i]); + } + return result; + } + + /// + /// Gets the line height in design units for a font, using the same + /// metric selection as GetLineHeightInPoints. + /// + private static int GetLineHeightDesignUnits(OpenTypeFont font) + { + if (font.Os2Table.UseTypoMetrics) + { + return font.Os2Table.sTypoAscender + - font.Os2Table.sTypoDescender + + font.Os2Table.sTypoLineGap; + } + else + { + return font.Os2Table.usWinAscent + + font.Os2Table.usWinDescent; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/UnicodeScriptClassifier.cs b/src/EPPlus.Fonts.OpenType/UnicodeScriptClassifier.cs new file mode 100644 index 0000000000..13a0bf6457 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/UnicodeScriptClassifier.cs @@ -0,0 +1,197 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/20/2026 EPPlus Software AB Initial implementation + 05/20/2026 EPPlus Software AB Auto-sort ranges so source can stay grouped by script + 05/25/2026 EPPlus Software AB Added CJK Symbols/Punctuation and Halfwidth/Fullwidth Forms + *************************************************************************************************/ +using OfficeOpenXml.Interfaces.Fonts; +using System; + +namespace EPPlus.Fonts.OpenType +{ + /// + /// Classifies Unicode code points into values. + /// Used during text shaping to route glyphs missing from the primary font to the + /// appropriate per-script fallback chain. + /// + /// Lookup is performed by binary search over a sorted range table, giving O(log n) + /// classification per code point. The table covers all supported scripts; code points + /// outside any range return . + /// + /// The source-code form of the table is grouped by script for readability. The actual + /// search table is built once at type initialization by sorting a copy by Start. + /// + internal static class UnicodeScriptClassifier + { + /// + /// Returns the Unicode script that contains the given code point, or + /// if the code point is not in any supported range. + /// + public static UnicodeScript OfCodePoint(uint codePoint) + { + // Binary search for the range containing codePoint. Ranges are sorted by Start + // and are non-overlapping. + int lo = 0; + int hi = _sortedRanges.Length - 1; + + while (lo <= hi) + { + int mid = lo + ((hi - lo) >> 1); + var range = _sortedRanges[mid]; + + if (codePoint < range.Start) + { + hi = mid - 1; + } + else if (codePoint > range.End) + { + lo = mid + 1; + } + else + { + return range.Script; + } + } + + return UnicodeScript.Unknown; + } + + private readonly struct Range + { + public readonly uint Start; + public readonly uint End; + public readonly UnicodeScript Script; + + public Range(uint start, uint end, UnicodeScript script) + { + Start = start; + End = end; + Script = script; + } + } + + // Source-form table — grouped by script for readability. Order does NOT matter here; + // the actual search table (_sortedRanges) is built by sorting this by Start. Ranges + // must still be non-overlapping; that invariant is not enforced. + // Coverage focuses on what realistically appears in Office documents; obscure scripts + // and historic blocks are omitted. + private static readonly Range[] _sourceRanges = new Range[] + { + // Latin + new Range(0x0020, 0x007F, UnicodeScript.Latin), // Basic Latin (ASCII) + new Range(0x00A0, 0x024F, UnicodeScript.Latin), // Latin-1 Supplement + Latin Extended-A/B + new Range(0x1E00, 0x1EFF, UnicodeScript.Latin), // Latin Extended Additional + new Range(0x2C60, 0x2C7F, UnicodeScript.Latin), // Latin Extended-C + + // Greek + new Range(0x0370, 0x03FF, UnicodeScript.Greek), // Greek and Coptic + new Range(0x1F00, 0x1FFF, UnicodeScript.Greek), // Greek Extended + + // Cyrillic + new Range(0x0400, 0x04FF, UnicodeScript.Cyrillic), // Cyrillic + new Range(0x0500, 0x052F, UnicodeScript.Cyrillic), // Cyrillic Supplement + new Range(0x2DE0, 0x2DFF, UnicodeScript.Cyrillic), // Cyrillic Extended-A + new Range(0xA640, 0xA69F, UnicodeScript.Cyrillic), // Cyrillic Extended-B + + // Hebrew + new Range(0x0590, 0x05FF, UnicodeScript.Hebrew), // Hebrew + + // Arabic + new Range(0x0600, 0x06FF, UnicodeScript.Arabic), // Arabic + new Range(0x0750, 0x077F, UnicodeScript.Arabic), // Arabic Supplement + new Range(0x08A0, 0x08FF, UnicodeScript.Arabic), // Arabic Extended-A + new Range(0xFB50, 0xFDFF, UnicodeScript.Arabic), // Arabic Presentation Forms-A + new Range(0xFE70, 0xFEFF, UnicodeScript.Arabic), // Arabic Presentation Forms-B + + // Devanagari + new Range(0x0900, 0x097F, UnicodeScript.Devanagari), // Devanagari + + // Thai + new Range(0x0E00, 0x0E7F, UnicodeScript.Thai), // Thai + + // Currency + new Range(0x20A0, 0x20CF, UnicodeScript.Currency), // Currency Symbols + + // Math + new Range(0x2200, 0x22FF, UnicodeScript.Math), // Mathematical Operators + new Range(0x27C0, 0x27EF, UnicodeScript.Math), // Miscellaneous Mathematical Symbols-A + new Range(0x2980, 0x29FF, UnicodeScript.Math), // Miscellaneous Mathematical Symbols-B + new Range(0x2A00, 0x2AFF, UnicodeScript.Math), // Supplemental Mathematical Operators + new Range(0x1D400, 0x1D7FF, UnicodeScript.Math), // Mathematical Alphanumeric Symbols + + // Symbol (box drawing, geometric shapes, dingbats, misc symbols) + new Range(0x2500, 0x257F, UnicodeScript.Symbol), // Box Drawing + new Range(0x2580, 0x259F, UnicodeScript.Symbol), // Block Elements + new Range(0x25A0, 0x25FF, UnicodeScript.Symbol), // Geometric Shapes + new Range(0x2700, 0x27BF, UnicodeScript.Symbol), // Dingbats + + // CJK Han (Unified Ideographs) + // + // Two extra ranges below are pragmatically classified as Han even though they are + // shared across Chinese, Japanese, and Korean writing: + // * CJK Symbols and Punctuation (U+3000-U+303F) — covers the ideographic full + // stop, ideographic comma, fullwidth space, brackets, etc. + // * Halfwidth and Fullwidth Forms (U+FF00-U+FFEF) — covers the fullwidth comma, + // fullwidth ASCII variants, halfwidth Katakana, halfwidth Hangul Jamo, etc. + // These ranges are shared CJK punctuation/forms, not specifically Han characters. + // In a single-language document a more accurate classification would route them + // to the document's primary script (Hiragana/Katakana for Japanese, Hangul for + // Korean, Han for Chinese). But without language detection we cannot do that. + // Routing them to Han is acceptable in practice because all major CJK fonts — + // Yu Gothic, Microsoft YaHei, Malgun Gothic, etc. — contain the same glyphs for + // these code points. + new Range(0x3000, 0x303F, UnicodeScript.Han), // CJK Symbols and Punctuation + new Range(0x3400, 0x4DBF, UnicodeScript.Han), // CJK Unified Ideographs Extension A + new Range(0x4E00, 0x9FFF, UnicodeScript.Han), // CJK Unified Ideographs + new Range(0xF900, 0xFAFF, UnicodeScript.Han), // CJK Compatibility Ideographs + new Range(0xFF00, 0xFFEF, UnicodeScript.Han), // Halfwidth and Fullwidth Forms + new Range(0x20000, 0x2A6DF, UnicodeScript.Han), // CJK Unified Ideographs Extension B + new Range(0x2A700, 0x2B73F, UnicodeScript.Han), // CJK Unified Ideographs Extension C + new Range(0x2B740, 0x2B81F, UnicodeScript.Han), // CJK Unified Ideographs Extension D + new Range(0x2B820, 0x2CEAF, UnicodeScript.Han), // CJK Unified Ideographs Extension E + + // Japanese Hiragana + new Range(0x3040, 0x309F, UnicodeScript.Hiragana), // Hiragana + + // Japanese Katakana + new Range(0x30A0, 0x30FF, UnicodeScript.Katakana), // Katakana + new Range(0x31F0, 0x31FF, UnicodeScript.Katakana), // Katakana Phonetic Extensions + + // Korean Hangul + new Range(0x1100, 0x11FF, UnicodeScript.Hangul), // Hangul Jamo + new Range(0x3130, 0x318F, UnicodeScript.Hangul), // Hangul Compatibility Jamo + new Range(0xAC00, 0xD7AF, UnicodeScript.Hangul), // Hangul Syllables + new Range(0xD7B0, 0xD7FF, UnicodeScript.Hangul), // Hangul Jamo Extended-B + + // Emoji + new Range(0x1F300, 0x1F5FF, UnicodeScript.Emoji), // Miscellaneous Symbols and Pictographs + new Range(0x1F600, 0x1F64F, UnicodeScript.Emoji), // Emoticons + new Range(0x1F680, 0x1F6FF, UnicodeScript.Emoji), // Transport and Map Symbols + new Range(0x1F700, 0x1F77F, UnicodeScript.Emoji), // Alchemical Symbols + new Range(0x1F780, 0x1F7FF, UnicodeScript.Emoji), // Geometric Shapes Extended + new Range(0x1F800, 0x1F8FF, UnicodeScript.Emoji), // Supplemental Arrows-C + new Range(0x1F900, 0x1F9FF, UnicodeScript.Emoji), // Supplemental Symbols and Pictographs + new Range(0x1FA00, 0x1FA6F, UnicodeScript.Emoji), // Chess Symbols + new Range(0x1FA70, 0x1FAFF, UnicodeScript.Emoji) // Symbols and Pictographs Extended-A + }; + + // Search table: copy of _sourceRanges sorted by Start. Built once at type init. + private static readonly Range[] _sortedRanges = BuildSortedRanges(); + + private static Range[] BuildSortedRanges() + { + var copy = new Range[_sourceRanges.Length]; + Array.Copy(_sourceRanges, copy, _sourceRanges.Length); + Array.Sort(copy, (a, b) => a.Start.CompareTo(b.Start)); + return copy; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Utils/ArrayPoolHelper.cs b/src/EPPlus.Fonts.OpenType/Utils/ArrayPoolHelper.cs new file mode 100644 index 0000000000..4f0c13b81d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/ArrayPoolHelper.cs @@ -0,0 +1,239 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/23/2025 EPPlus Software AB ArrayPoolHelper implementation + *************************************************************************************************/ +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER +using System.Buffers; +#endif +using System; + +namespace EPPlus.Fonts.OpenType.Utilities +{ + /// + /// Helper class for array pooling with fallback to regular allocation on older frameworks. + /// Provides a consistent API across all .NET versions. + /// + internal static class ArrayPoolHelper + { +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + private static readonly ArrayPool Pool = ArrayPool.Shared; +#endif + // Cache empty array for .NET 3.5 compatibility (Array.Empty() was added in .NET 4.6) + private static readonly T[] EmptyArray = new T[0]; + + /// + /// Rents an array from the pool (or allocates a new one in older targets). + /// The returned array may be larger than the requested minimum length. + /// + /// Minimum required array length + /// An array with at least minimumLength elements + public static T[] Rent(int minimumLength) + { + if (minimumLength < 0) + { + throw new ArgumentOutOfRangeException(nameof(minimumLength), "Minimum length must be non-negative"); + } + + if (minimumLength == 0) + { + return EmptyArray; + } + +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + return Pool.Rent(minimumLength); +#else + return new T[minimumLength]; +#endif + } + + /// + /// Returns the array to the pool (does nothing in older targets). + /// + /// Array to return + /// If true, clears the array before returning to pool + public static void Return(T[] array, bool clearArray = false) + { +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + if (array != null && array.Length > 0) + { + Pool.Return(array, clearArray); + } +#endif + // In older targets: let GC handle the array + } + + /// + /// Safely returns the array to the pool and sets the reference to null. + /// This prevents accidental reuse of returned arrays. + /// + /// Reference to array to return + /// If true, clears the array before returning to pool + public static void SafeReturn(ref T[] array, bool clearArray = false) + { + if (array != null && array.Length > 0) + { +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + Pool.Return(array, clearArray); +#endif + array = null; + } + } + + /// + /// Ensures an array has at least the specified capacity. + /// If the current array is too small, returns it to the pool and rents a larger one. + /// If the current array is sufficient, returns it unchanged. + /// + /// Current array (may be null) + /// Tracked capacity of current array + /// Required minimum length + /// If true and a new array is rented, clears it + /// Array with at least minimumLength capacity + public static T[] EnsureCapacity(ref T[] array, ref int currentCapacity, int minimumLength, bool clearArray = false) + { + if (minimumLength < 0) + { + throw new ArgumentOutOfRangeException(nameof(minimumLength), "Minimum length must be non-negative"); + } + + if (minimumLength == 0) + { + return EmptyArray; + } + + // If we already have a sufficient array, return it + if (array != null && currentCapacity >= minimumLength) + { + return array; + } + + // Return old array to pool + if (array != null && array.Length > 0) + { +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + Pool.Return(array, clearArray: false); +#endif + } + + // Rent new array +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER + array = Pool.Rent(minimumLength); + currentCapacity = array.Length; + + if (clearArray) + { + Array.Clear(array, 0, array.Length); + } +#else + array = new T[minimumLength]; + currentCapacity = minimumLength; +#endif + + return array; + } + + /// + /// Rents an array and copies data from source array. + /// Useful for resizing operations. + /// + /// Source array to copy from + /// Number of elements to copy from source + /// Minimum length of new array (must be >= sourceLength) + /// New array with copied data + public static T[] RentAndCopy(T[] source, int sourceLength, int minimumLength) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (sourceLength < 0 || sourceLength > source.Length) + { + throw new ArgumentOutOfRangeException(nameof(sourceLength)); + } + + if (minimumLength < sourceLength) + { + throw new ArgumentException("Minimum length must be at least sourceLength", nameof(minimumLength)); + } + + var newArray = Rent(minimumLength); + + if (sourceLength > 0) + { + Array.Copy(source, 0, newArray, 0, sourceLength); + } + + return newArray; + } + + /// + /// Creates a scope that automatically returns the array when disposed. + /// Usage: using (var scope = ArrayPoolHelper{T}.RentScoped(100)) { ... } + /// + /// Minimum required array length + /// If true, clears the array before returning to pool + /// A disposable scope containing the rented array + public static RentedArrayScope RentScoped(int minimumLength, bool clearOnReturn = false) + { + return new RentedArrayScope(Rent(minimumLength), clearOnReturn); + } + + /// + /// Disposable wrapper for rented arrays that ensures they are returned to the pool. + /// + public struct RentedArrayScope : IDisposable + { + private T[] _array; + private readonly bool _clearOnReturn; + private bool _disposed; + + internal RentedArrayScope(T[] array, bool clearOnReturn) + { + _array = array; + _clearOnReturn = clearOnReturn; + _disposed = false; + } + + /// + /// Gets the rented array. + /// + public T[] Array + { + get + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(RentedArrayScope)); + } + return _array; + } + } + + /// + /// Gets the length of the rented array. + /// + public int Length => _array?.Length ?? 0; + + /// + /// Returns the array to the pool. + /// + public void Dispose() + { + if (!_disposed && _array != null) + { + ArrayPoolHelper.Return(_array, _clearOnReturn); + _array = null; + _disposed = true; + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Utils/CharacterUtil.cs b/src/EPPlus.Fonts.OpenType/Utils/CharacterUtil.cs new file mode 100644 index 0000000000..50a580972e --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/CharacterUtil.cs @@ -0,0 +1,101 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/23/2025 EPPlus Software AB ArrayPoolHelper implementation + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Utils +{ + internal class CharacterUtil + { + /// + /// Extracts Unicode code points from a char array. + /// Correctly handles surrogate pairs. + /// + public static IEnumerable ExtractCodePointsFromChars(char[] chars) + { + var codePoints = new HashSet(); + + int i = 0; + while (i < chars.Length) + { + if (i < chars.Length - 1 && char.IsHighSurrogate(chars[i])) + { + char high = chars[i]; + char low = chars[i + 1]; + + if (char.IsLowSurrogate(low)) + { + // Valid surrogate pair - convert to code point + int codePoint = char.ConvertToUtf32(high, low); + codePoints.Add(codePoint); + i += 2; // Skip both surrogate chars + continue; + } + else + { + // Invalid - skip high surrogate alone + i++; + continue; + } + } + else if (char.IsLowSurrogate(chars[i])) + { + // Lone low surrogate - skip it + i++; + continue; + } + else + { + // Normal BMP character + codePoints.Add(chars[i]); + i++; + } + } + + return codePoints; + } + + /// + /// Extracts Unicode code points from a string. + /// Correctly handles surrogate pairs. + /// + public static IEnumerable ExtractCodePointsFromString(string text) + { + var codePoints = new HashSet(); + + for (int i = 0; i < text.Length; i++) + { + if (char.IsHighSurrogate(text[i])) + { + if (i + 1 < text.Length && char.IsLowSurrogate(text[i + 1])) + { + // Valid surrogate pair + int codePoint = char.ConvertToUtf32(text[i], text[i + 1]); + codePoints.Add(codePoint); + i++; // Skip low surrogate in next iteration + } + // else: Invalid high surrogate alone - skip it + } + else if (char.IsLowSurrogate(text[i])) + { + // Lone low surrogate - skip it + } + else + { + // Normal BMP character + codePoints.Add(text[i]); + } + } + + return codePoints; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Utils/ChecksumCalculator.cs b/src/EPPlus.Fonts.OpenType/Utils/ChecksumCalculator.cs new file mode 100644 index 0000000000..c1d30e15f5 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/ChecksumCalculator.cs @@ -0,0 +1,78 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Fonts.OpenType.Utils +{ + internal static class ChecksumCalculator + { + + /// + /// Calculates the checksum for a table according to OpenType spec. + /// Pads the data to a multiple of 4 bytes and interprets values as big-endian. + /// + + public static uint CalculateTableChecksum(byte[] data, string tag) + { + + if (tag == "head" && data.Length >= 12) + { + data = (byte[])data.Clone(); // Make a copy so we don't modify original + for (int i = 8; i < 12; i++) + { + data[i] = 0; + } + } + + uint sum = 0; + int length = data.Length; + int paddedLength = ((length + 3) / 4) * 4; // Round up to multiple of 4 + for (int i = 0; i < paddedLength; i += 4) + { + uint value = 0; + for (int b = 0; b < 4; b++) + { + int index = i + b; + byte byteValue = (index < length) ? data[index] : (byte)0; + value = (value << 8) | byteValue; // Big-endian shift + } + sum += value; + } + return sum; + } + + + /// + /// Calculates the checksum for the entire font file. + /// The head.checkSumAdjustment field must be set to 0 before calling this. + /// + public static uint CalculateFontChecksum(byte[] fontData) + { + uint sum = 0; + int length = fontData.Length; + int paddedLength = ((length + 3) / 4) * 4; + + for (int i = 0; i < paddedLength; i += 4) + { + uint value = 0; + for (int b = 0; b < 4; b++) + { + int index = i + b; + byte byteValue = (index < length) ? fontData[index] : (byte)0; + value = (value << 8) | byteValue; + } + sum += value; + } + return sum; + } + + } +} diff --git a/src/EPPlus.Fonts.OpenType/Utils/CodePointUtil.cs b/src/EPPlus.Fonts.OpenType/Utils/CodePointUtil.cs new file mode 100644 index 0000000000..c427caa184 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/CodePointUtil.cs @@ -0,0 +1,85 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace EPPlus.Fonts.OpenType.Utils +{ + internal static class CodePointUtil + { + /// + /// Extracts distinct Unicode code points from a sequence of chars, + /// correctly combining surrogate pairs into supplementary plane code points. + /// Lone surrogates are skipped. + /// + internal static IEnumerable ExtractCodePoints(IEnumerable chars) + { + var codePoints = new HashSet(); + char? pendingHighSurrogate = null; + + foreach (var c in chars) + { + if (pendingHighSurrogate.HasValue) + { + if (char.IsLowSurrogate(c)) + { + // Valid pair - combine into code point + int cp = char.ConvertToUtf32(pendingHighSurrogate.Value, c); + codePoints.Add(cp); + pendingHighSurrogate = null; + continue; + } + + // Previous high surrogate had no matching low - skip it + pendingHighSurrogate = null; + } + + if (char.IsHighSurrogate(c)) + { + pendingHighSurrogate = c; + } + else if (!char.IsLowSurrogate(c)) + { + // Normal BMP character + codePoints.Add(c); + } + // Lone low surrogates are skipped + } + + return codePoints; + } + + /// + /// Converts a set of Unicode code points to a string, + /// correctly encoding supplementary plane characters as surrogate pairs. + /// + internal static string CodePointsToString(HashSet codePoints) + { + var sb = new System.Text.StringBuilder(codePoints.Count * 2); + + foreach (var cp in codePoints) + { + if (cp <= 0xFFFF) + { + sb.Append((char)cp); + } + else + { + // Supplementary plane - encode as surrogate pair + sb.Append(char.ConvertFromUtf32(cp)); + } + } + + return sb.ToString(); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Utils/EnumUtil.cs b/src/EPPlus.Fonts.OpenType/Utils/EnumUtil.cs new file mode 100644 index 0000000000..2f6efd180c --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/EnumUtil.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Utils +{ + internal static class EnumUtil + { + + #if (!NET35) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + #endif + public static bool HasFlag(T value, T flag) where T : Enum + { + return (Convert.ToInt32(value) & Convert.ToInt32(flag)) == Convert.ToInt32(flag); + } + #if (!NET35) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + #endif + public static bool HasNotFlag(T value, T flag) where T : Enum + { + return (Convert.ToInt32(value) & Convert.ToInt32(flag)) != Convert.ToInt32(flag); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Utils/LayoutTableSerializationHelper.cs b/src/EPPlus.Fonts.OpenType/Utils/LayoutTableSerializationHelper.cs new file mode 100644 index 0000000000..f405dfd745 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/LayoutTableSerializationHelper.cs @@ -0,0 +1,45 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/12/2026 EPPlus Software AB Helper for layout table serialization + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Tables; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Utils +{ + /// + /// Helper methods for serializing OpenType layout tables (GSUB, GPOS, GDEF, etc.). + /// + internal static class LayoutTableSerializationHelper + { + /// + /// Updates an offset placeholder and serializes an element. + /// Common pattern used by layout tables to write sub-tables. + /// + /// Binary writer + /// Start position of the main table + /// Position where offset placeholder was written + /// Element to serialize + public static void UpdateOffsetAndSerialize(FontsBinaryWriter writer, long tableStart, long placeholderPos, FontTableElement element) + { + ushort offset = (ushort)(writer.BaseStream.Position - tableStart); + long resumePos = writer.BaseStream.Position; + + // Update placeholder with calculated offset + writer.BaseStream.Seek(placeholderPos, SeekOrigin.Begin); + writer.WriteUInt16BigEndian(offset); + + // Resume and serialize element + writer.BaseStream.Seek(resumePos, SeekOrigin.Begin); + element.Serialize(writer); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Utils/Platform/PlatformUtils.cs b/src/EPPlus.Fonts.OpenType/Utils/Platform/PlatformUtils.cs new file mode 100644 index 0000000000..5042bfe664 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/Platform/PlatformUtils.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System; +using System.IO; + +namespace EPPlus.Fonts.OpenType.Utils.Platform +{ + internal class PlatformUtils + { + public enum OperatingSystem + { + Windows, + Mac, + Linux, + Unknown + } + + public static OperatingSystem GetPlatform() + { + PlatformID platform = Environment.OSVersion.Platform; + if (platform == PlatformID.Win32NT || platform == PlatformID.Win32Windows || + platform == PlatformID.Win32S || platform == PlatformID.WinCE) + { + return OperatingSystem.Windows; + } + if (platform == PlatformID.MacOSX) + { + return OperatingSystem.Mac; + } + if (platform == PlatformID.Unix) + { + // macOS has this folder; Linux doesn't + if (Directory.Exists("/System/Library/CoreServices")) + return OperatingSystem.Mac; + + return OperatingSystem.Linux; + } + return OperatingSystem.Unknown; + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/Utils/StringBuilderExtensions.cs b/src/EPPlus.Fonts.OpenType/Utils/StringBuilderExtensions.cs new file mode 100644 index 0000000000..480c4325e9 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/StringBuilderExtensions.cs @@ -0,0 +1,145 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/26/2026 EPPlus Software AB StringBuilder extensions for readability + *************************************************************************************************/ +using System.Collections.Generic; +using System.Text; + +namespace EPPlus.Fonts.OpenType.Utilities +{ + /// + /// Extension methods for StringBuilder to improve code readability in text wrapping. + /// + internal static class StringBuilderExtensions + { + /// + /// Clears the StringBuilder content. + /// More readable than: builder.Length = 0; + /// + public static void Clear(this StringBuilder builder) + { + builder.Length = 0; + } + + /// + /// Checks if the StringBuilder is empty. + /// More readable than: builder.Length == 0 + /// + public static bool IsEmpty(this StringBuilder builder) + { + return builder.Length == 0; + } + + /// + /// Checks if the StringBuilder has content. + /// More readable than: builder.Length > 0 + /// + public static bool HasContent(this StringBuilder builder) + { + return builder.Length > 0; + } + + /// + /// Gets the last character without removing it. + /// Returns '\0' if empty. + /// + public static char LastChar(this StringBuilder builder) + { + if (builder.Length == 0) + return '\0'; + + return builder[builder.Length - 1]; + } + + /// + /// Checks if the last character is a space. + /// More readable than: builder[builder.Length - 1] == ' ' + /// + public static bool EndsWithSpace(this StringBuilder builder) + { + return builder.Length > 0 && builder[builder.Length - 1] == ' '; + } + + /// + /// Removes trailing space if present. + /// More readable than: if (builder.Length > 0 && builder[builder.Length - 1] == ' ') builder.Length--; + /// + public static void TrimTrailingSpace(this StringBuilder builder) + { + if (builder.Length > 0 && builder[builder.Length - 1] == ' ') + { + builder.Length--; + } + } + + /// + /// Appends a space if the builder is not empty. + /// Useful for word separation. + /// + public static void AppendSpaceIfNotEmpty(this StringBuilder builder) + { + if (builder.Length > 0) + { + builder.Append(' '); + } + } + + /// + /// Appends text from a substring without creating intermediate string. + /// Wraps the 3-parameter Append for better readability. + /// + public static void AppendSubstring(this StringBuilder builder, string text, int startIndex, int length) + { + builder.Append(text, startIndex, length); + } + + /// + /// Ensures minimum capacity without excessive allocation. + /// More readable than: if (builder.Capacity < minCapacity) builder.Capacity = minCapacity; + /// + public static void EnsureCapacity(this StringBuilder builder, int minimumCapacity) + { + if (builder.Capacity < minimumCapacity) + { + builder.Capacity = minimumCapacity; + } + } + + /// + /// Returns the content as string and clears the builder. + /// Useful for "flush" pattern. + /// + public static string ToStringAndClear(this StringBuilder builder) + { + string result = builder.ToString(); + builder.Length = 0; + return result; + } + + /// + /// Adds the current line to a list after trimming trailing space. + /// Clears the builder afterwards. + /// Encapsulates the common "finalize line" pattern. + /// + public static void FlushToList(this StringBuilder builder, List lines) + { + if (builder.Length > 0) + { + builder.TrimTrailingSpace(); + if (builder.Length > 0) + { + lines.Add(builder.ToString()); + } + builder.Clear(); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/Utils/TextUtils.cs b/src/EPPlus.Fonts.OpenType/Utils/TextUtils.cs new file mode 100644 index 0000000000..12b82fb4ba --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/Utils/TextUtils.cs @@ -0,0 +1,63 @@ +using OfficeOpenXml.Drawing; +using System; +using System.Globalization; + +namespace EPPlus.Fonts.OpenType.Utils +{ + public static class TextUtils + { + public const int EMU_PER_POINT = 12700; + public const int EMU_PER_PIXEL = 9525; + + public static double PointToPixel(this double pointSize) + { + //1 inch is 72 pts. "Inches * dots/inch = dots" aka Pixels + return pointSize / 72 * 96; + } + public static string PointToPixelString(this double pointSize, string format=null) + { + //1 inch is 72 pts. "Inches * dots/inch = dots" aka Pixels + var pixelSize = pointSize / 72 * 96; + if (format != null) + { + return pixelSize.ToString(format, CultureInfo.InvariantCulture); + } + return pixelSize.ToString(CultureInfo.InvariantCulture); + } + + public static double PointToPixel(this double pointSize, bool isFonts) + { + return PointToPixel(pointSize); + } + + public static float PointToPixel(this float pointSize) + { + //1 inch is 72 pts. "Inches * dots/inch = dots" aka Pixels + return pointSize / 72 * 96; + } + + public static double PixelToPoint(this double pixelSize) + { + //var roundedSize = (double)RoundToWhole(pixelSize); + return pixelSize / 96 * 72; + } + + public static double EmuToPoint(this double emuNumber) + { + return emuNumber / EMU_PER_POINT; + } + + + public static double EmuToPixels(this double? emuNumber) => emuNumber.HasValue ? emuNumber.Value.EmuToPixels() : 0D; + + public static double EmuToPixels(this double emuNumber) + { + return emuNumber / EMU_PER_PIXEL; + } + + public static int RoundToWhole(double number) + { + return (int)Math.Round(number, 0, MidpointRounding.AwayFromZero); + } + } +} diff --git a/src/EPPlus.Fonts.OpenType/license.md b/src/EPPlus.Fonts.OpenType/license.md new file mode 100644 index 0000000000..6a25e1654d --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/license.md @@ -0,0 +1,131 @@ +# Polyform Noncommercial License 1.0.0 + + + +## Acceptance + +In order to get any license under these terms, you must agree +to them as both strict obligations and conditions to all +your licenses. + +## Copyright License + +The licensor grants you a copyright license for the +software to do everything you might do with the software +that would otherwise infringe the licensor's copyright +in it for any permitted purpose. However, you may +only distribute the software according to [Distribution +License](#distribution-license) and make changes or new works +based on the software according to [Changes and New Works +License](#changes-and-new-works-license). + +## Distribution License + +The licensor grants you an additional copyright license +to distribute copies of the software. Your license +to distribute covers distributing the software with +changes and new works permitted by [Changes and New Works +License](#changes-and-new-works-license). + +## Notices + +You must ensure that anyone who gets a copy of any part of +the software from you also gets a copy of these terms or the +URL for them above, as well as copies of any plain-text lines +beginning with `Required Notice:` that the licensor provided +with the software. For example: + +> Required Notice: Copyright Yoyodyne, Inc. (http://example.com) + +## Changes and New Works License + +The licensor grants you an additional copyright license to +make changes and new works based on the software for any +permitted purpose. + +## Patent License + +The licensor grants you a patent license for the software that +covers patent claims the licensor can license, or becomes able +to license, that you would infringe by using the software. + +## Noncommercial Purposes + +Any noncommercial purpose is a permitted purpose. + +## Personal Uses + +Personal use for research, experiment, and testing for +the benefit of public knowledge, personal study, private +entertainment, hobby projects, amateur pursuits, or religious +observance, without any anticipated commercial application, +is use for a permitted purpose. + +## Noncommercial Organizations + +Use by any charitable organization, educational institution, +public research organization, public safety or health +organization, environmental protection organization, +or government institution is use for a permitted purpose +regardless of the source of funding or obligations resulting +from the funding. + +## Fair Use + +You may have "fair use" rights for the software under the +law. These terms do not limit them. + +## No Other Rights + +These terms do not allow you to sublicense or transfer any of +your licenses to anyone else, or prevent the licensor from +granting licenses to anyone else. These terms do not imply +any other licenses. + +## Patent Defense + +If you make any written claim that the software infringes or +contributes to infringement of any patent, your patent license +for the software granted under these terms ends immediately. If +your company makes such a claim, your patent license ends +immediately for work on behalf of your company. + +## Violations + +The first time you are notified in writing that you have +violated any of these terms, or done anything with the software +not covered by your licenses, your licenses can nonetheless +continue if you come into full compliance with these terms, +and take practical steps to correct past violations, within +32 days of receiving notice. Otherwise, all your licenses +end immediately. + +## No Liability + +***As far as the law allows, the software comes as is, without +any warranty or condition, and the licensor will not be liable +to you for any damages arising out of these terms or the use +or nature of the software, under any kind of legal claim.*** + +## Definitions + +The **licensor** is the individual or entity offering these +terms, and the **software** is the software the licensor makes +available under these terms. + +**You** refers to the individual or entity agreeing to these +terms. + +**Your company** is any legal entity, sole proprietorship, +or other kind of organization that you work for, plus all +organizations that have control over, are under the control of, +or are under common control with that organization. **Control** +means ownership of substantially all the assets of an entity, +or the power to direct its management and policies by vote, +contract, or otherwise. Control can be direct or indirect. + +**Your licenses** are all the licenses granted to you for the +software under these terms. + +**Use** means anything you do with the software requiring one +of your licenses. \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/readme.md b/src/EPPlus.Fonts.OpenType/readme.md new file mode 100644 index 0000000000..8b893f59f9 --- /dev/null +++ b/src/EPPlus.Fonts.OpenType/readme.md @@ -0,0 +1,2 @@ +# EPPlus.Fonts.OpenType +Library for reading font data. \ No newline at end of file diff --git a/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.csproj b/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.csproj new file mode 100644 index 0000000000..d1c4d8a9dc --- /dev/null +++ b/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + latest + enable + True + EPPlus.Graphics.Tests.snk + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.snk b/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.snk new file mode 100644 index 0000000000..3acc75708f Binary files /dev/null and b/src/EPPlus.Graphics.Tests/EPPlus.Graphics.Tests.snk differ diff --git a/src/EPPlus.Graphics.Tests/GrahpicsTests.cs b/src/EPPlus.Graphics.Tests/GrahpicsTests.cs new file mode 100644 index 0000000000..c4529ea780 --- /dev/null +++ b/src/EPPlus.Graphics.Tests/GrahpicsTests.cs @@ -0,0 +1,253 @@ +using EPPlus.Graphics; +using EPPlus.Graphics.Units; +using EPPlus.Graphics.Geometry; +using System.Drawing; + +namespace EPPlus.Graphics.Tests +{ + [TestClass] + public class GraphicsTests + { + [TestMethod] + public void AddChildTest() + { + Transform p1 = new Transform(); + Transform c1 = new Transform(Vector2.One, Vector2.One, p1); + Assert.HasCount(1, p1.ChildObjects); + } + + [TestMethod] + public void MoveParentTransformTest() + { + Transform p1 = new Transform(); + Transform c1 = new Transform(Vector2.One, Vector2.One, p1); + p1.Translate(Vector2.One); + Assert.AreEqual(2, c1.Position.X); + Assert.AreEqual(1, c1.LocalPosition.X); + } + + [TestMethod] + public void ScaleParentTransformTest() + { + Transform p1 = new Transform(); + Transform c1 = new Transform(Vector2.One, Vector2.One, p1); + p1.Scale = new Vector2(2,2); + Assert.AreEqual(1, c1.LocalScale.X); + Assert.AreEqual(2, c1.Scale.X); + } + + [TestMethod] + public void ScaleMatrixTest() + { + var identity = Matrix3x3.Identity; + var scaleMatrix = new Matrix3x3(2, 0, 0, 2, 0, 0); + + var mtMult = identity * scaleMatrix; + + Assert.AreEqual(mtMult.A, scaleMatrix.A); + Assert.AreEqual(mtMult.B, scaleMatrix.B); + Assert.AreEqual(mtMult.C, scaleMatrix.C); + Assert.AreEqual(mtMult.D, scaleMatrix.D); + Assert.AreEqual(mtMult.E, scaleMatrix.E); + Assert.AreEqual(mtMult.F, scaleMatrix.F); + Assert.AreEqual(mtMult.G, scaleMatrix.G); + Assert.AreEqual(mtMult.H, scaleMatrix.H); + Assert.AreEqual(mtMult.I, scaleMatrix.I); + + var vect2 = Vector2.One* mtMult; + + Assert.AreEqual(2, vect2.X); + Assert.AreEqual(2, vect2.Y); + + var vect3 = new Vector2(2,2) * mtMult; + + Assert.AreEqual(4, vect3.X); + Assert.AreEqual(4, vect3.Y); + } + + [TestMethod] + public void ChildAndGrandChildLocalAndGlobal() + { + Transform p1 = new Transform(); + Transform c1 = new Transform(Vector2.One, Vector2.One, p1); + + Transform gc1 = new Transform(new Vector2(5, 5), Vector2.One, c1); + p1.Scale = new Vector2(0.5d, 0.5d); + + Assert.AreEqual(1, c1.LocalScale.X); + Assert.AreEqual(0.5, c1.Scale.X); + Assert.AreEqual(0.5, gc1.Scale.X); + + p1.Scale = new Vector2(1d, 1d); + + c1.Scale = new Vector2(0.5d, 0.5d); + + Assert.AreEqual(3.5, gc1.Position.X); + Assert.AreEqual(3.5, gc1.Position.Y); + //Assert.AreEqual(5, gc1.Position.X); + //Assert.AreEqual(5, gc1.Position.Y); + } + + + [TestMethod] + public void AttemptDirectScale() + { + Transform p1 = new Transform(); + p1.Scale = new Vector2(0.5d, 0.5d); + p1.LocalPosition = new Vector2(5, 5); + + + Assert.AreEqual(5d, p1.Position.X); + Assert.AreEqual(5d, p1.Position.Y); + } + + [TestMethod] + public void ChildAndGrandChildTest() + { + Transform p1 = new Transform(); + Transform c1 = new Transform(Vector2.One, Vector2.One, p1); + var grandChildPosition = new Vector2(1.5, 2.33333333); + + Transform c2 = new Transform(grandChildPosition, Vector2.One, c1); + + var posOffset = new Vector2(0.2, 1.1); + p1.Translate(posOffset); + + Assert.AreEqual(2.7, c2.Position.X); + Assert.AreEqual(4.43333333, c2.Position.Y); + Assert.AreEqual(1.5, c2.LocalPosition.X); + Assert.AreEqual(2.33333333, c2.LocalPosition.Y); + } + + [TestMethod] + public void ChildAndGrandChildTestLocalPos() + { + Transform p1 = new Transform(); + p1.LocalPosition = new Vector2(2, 2); + + Transform c1 = new Transform(); + c1.Parent = p1; + + c1.LocalPosition = new Vector2(5, 5); + + Transform gc1 = new Transform(); + + //Statics in vector2 are unintentionally remaining? + Assert.AreEqual(0, gc1.LocalPosition.X); + Assert.AreEqual(0, gc1.LocalPosition.Y); + } + + [TestMethod] + public void ChildAndGrandChildTestLocalPosOtherConstructor() + { + var startPos = new Vector2(2, 2); + Transform p1 = new Transform(startPos, Vector2.One); + + var localStartPosC1 = new Vector2(5, 5); + Transform c1 = new Transform(); + c1.Parent = p1; + + c1.LocalPosition = localStartPosC1; + + Transform gc1 = new Transform(); + + gc1.Parent = c1; + + var localGC1 = new Vector2(10, 10); + gc1.LocalPosition = localGC1; + + Assert.AreEqual(2, p1.LocalPosition.X); + Assert.AreEqual(2, p1.LocalPosition.Y); + + Assert.AreEqual(5, c1.LocalPosition.X); + Assert.AreEqual(5, c1.LocalPosition.Y); + + Assert.AreEqual(10, gc1.LocalPosition.X); + Assert.AreEqual(10, gc1.LocalPosition.Y); + } + + [TestMethod] + public void SettingGlobalPositionOfParent() + { + Transform p1 = new Transform(new Vector2(3,3), Vector2.One); + + //This gets an all new vector2 with the position of p1 in the world + var worldPosition = p1.Position; + worldPosition.Y = 5; + worldPosition.X = 10; + + p1.Position = worldPosition; + + Assert.AreEqual(5, p1.LocalPosition.Y); + Assert.AreEqual(5, p1.Position.Y); + } + + + [TestMethod] + public void SettingLocalPositionOfBase() + { + Transform p1 = new Transform(new Vector2(3, 3), Vector2.One); + + Assert.AreEqual(3, p1.Position.Y); + Assert.AreEqual(3, p1.LocalPosition.Y); + Assert.AreEqual(p1.Position.Y, p1.LocalPosition.Y); + + p1.LocalPosition = new(p1.LocalPosition.X, 5); + Assert.AreEqual(p1.Position.Y, 5); + Assert.AreEqual(5, p1.LocalPosition.Y); + } + + [TestMethod] + public void BoundingBoxes() + { + BoundingBox Shape = new BoundingBox(); + + Shape.Position = new Vector2(2,2); + Shape.Size = Vector2.One; + Shape.Name = "ShapeTransform"; + + Shape.Width = 10; + Shape.Height = 10; + + BoundingBox TextBody = new BoundingBox(); + + TextBody.Parent = Shape; + TextBody.Name = "TextBodyTransform"; + + TextBody.Width = 20; + TextBody.Height = 20; + + TextBody.LocalPosition = new(10, 11); + + Assert.AreEqual(10, TextBody.LocalPosition.X); + Assert.AreEqual(11, TextBody.LocalPosition.Y); + + BoundingBox Paragraph1 = new BoundingBox(); + Paragraph1.Name = "Paragraph1Transform"; + Paragraph1.Parent = TextBody; + Paragraph1.Width = 5; + Paragraph1.Height = 5; + + + Paragraph1.LocalPosition = new Vector2(5, 8); + + Assert.AreEqual(10, TextBody.LocalPosition.X); + Assert.AreEqual(11, TextBody.LocalPosition.Y); + + Assert.AreEqual(2, Shape.LocalPosition.X); + Assert.AreEqual(2, Shape.LocalPosition.Y); + + Assert.AreEqual(10, Shape.ChildObjects[0].LocalPosition.X); + Assert.AreEqual(11, Shape.ChildObjects[0].LocalPosition.Y); + + Assert.AreEqual(5, Paragraph1.LocalPosition.X); + Assert.AreEqual(8, Paragraph1.LocalPosition.Y); + + Assert.AreEqual(Paragraph1.Position.X, 17); + Assert.AreEqual(Paragraph1.Position.Y, 21); + + + var str = Shape.ToHierarchyString(); + } + } +} diff --git a/src/EPPlus.Graphics.Tests/MSTestSettings.cs b/src/EPPlus.Graphics.Tests/MSTestSettings.cs new file mode 100644 index 0000000000..aaf278c844 --- /dev/null +++ b/src/EPPlus.Graphics.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/EPPlus.Graphics.Tests/publickey.snk b/src/EPPlus.Graphics.Tests/publickey.snk new file mode 100644 index 0000000000..2f59d52cde Binary files /dev/null and b/src/EPPlus.Graphics.Tests/publickey.snk differ diff --git a/src/EPPlus.Graphics/AssemblyInfo.cs b/src/EPPlus.Graphics/AssemblyInfo.cs new file mode 100644 index 0000000000..31a1e461b7 --- /dev/null +++ b/src/EPPlus.Graphics/AssemblyInfo.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// In SDK-style projects such as this one, several assembly attributes that were historically +// defined in this file are now automatically added during build and populated with +// values defined in project properties. For details of which attributes are included +// and how to customise this process see: https://aka.ms/assembly-info-properties + + +// Setting ComVisible to false makes the types in this assembly not visible to COM +// components. If you need to access a type in this assembly from COM, set the ComVisible +// attribute to true on that type. + +[assembly: ComVisible(false)] +[assembly: AllowPartiallyTrustedCallers] + +// The following GUID is for the ID of the typelib if this project is exposed to COM. + +[assembly: Guid("60855b7d-19da-4dfa-90b2-78231d227d65")] +[assembly: InternalsVisibleTo("EPPlus.Export.Pdf, PublicKey=00240000048000009400000006020000002400005253413100040000010001005dd165010a983c48dcdee4d91434cd53fbc1651ba55263e9be73f5fc07ec63a666c90f3d9de7356c9214f461bae351a0375c5d75db0a9b45800bd347b81559c5a0bc84313de08d5d278b693e7da96678aa17d00fc8b825e37c0e28142c64cf6e7d174ebd11dc04142eb2ad438ca137f324ad9757bf02279a5f7a9d7479afbcb0")] +[assembly: InternalsVisibleTo("EPPlus.Graphics.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001007d8a723b0b7fb46228350d1fc0fe88397cba2fb8354e39fe04bfe37ca3b44c438557ff8139fd513b63ca2731c516ff4820a3ce0a72f6c235ab774a323075f4db62434ffffa6e68c8f260701fd175b06df24f6d09dab9dc4eb8b043160513810d1f14b9b26c29d7f9bfd91897e1a35de3279cd5d8f62de015e967a93bffb41fa9")] + +[assembly: InternalsVisibleTo("EPPlus.Export.ImageRenderer, PublicKey=002400000480000094000000060200000024000052534131000400000100010045e5d8275ad7edb388eb9c60ac6e1dd30161aea53f5334c45751217df06feb6ae799a1866fc0671f9ec0d6dbec23807ad71012617cb8d471979216c63baa607754a5d5f20b45e1ce5c256685552a2a09e19a35b554d554dcbbfecdd331bf15cb2b5c4fbd76f7424f30493635c0234ee1ea782ebfdfdc0dec3dbbc167c4c061cc")] +[assembly: InternalsVisibleTo("EPPlus.Export.ImageRenderer.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010065aa00a9b0dcfa0e8debefb14c3b6c12ef658ce1cfbfafcb6eb7dbdc0c49e4f70ea144ba29d827453f0716ffc8c1d87450ce0cf255bda1def174915caaa78f373f291ce1a7edf91ba6f9dc961d937b19d46dd5d7d70a6e2097c749d43780f0d00b29a6f5aec5c1d191bee69de0c889a6d2566bef3cb235612351eae7015382d0")] \ No newline at end of file diff --git a/src/EPPlus.Graphics/BoundingBox.cs b/src/EPPlus.Graphics/BoundingBox.cs new file mode 100644 index 0000000000..9147c49987 --- /dev/null +++ b/src/EPPlus.Graphics/BoundingBox.cs @@ -0,0 +1,128 @@ +using EPPlus.Graphics.Geometry; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Graphics +{ + public class BoundingBox : Transform + { + public BoundingBox() : base() + { + } + + public BoundingBox(double width, double height) : base(0, 0, width, height) + { + } + public BoundingBox(double left, double top, double width, double height) : base(left, top, width, height) + { + } + + /// + /// Y pos (min) + /// + public double Top + { + get { return LocalPosition.Y; } + set + { + LocalPosition = new Vector2(LocalPosition.X, value); + //var tmpHeight = Height != 0 ? Height : 0; + + //var currentPosition = Transform.LocalPosition; + //currentPosition.Y = value; + //Transform.LocalPosition = currentPosition; + + ////Recalculate bottom position correctly + ////if (tmpHeight != 0) + ////{ + // //Height = tmpHeight; + // Bottom = Top + tmpHeight; + ////} + } + } + /// + /// X pos (min) + /// + public double Left + { + get { return LocalPosition.X; } + set + { + //var tmpWidth = Width != 0 ? Width : 0; + + //var currentPosition = Transform.LocalPosition; + //currentPosition.X = value; + //Transform.LocalPosition = currentPosition; + + //Recalculate Right position correctly + //if (tmpWidth != 0) + //{ + //Right = Left + tmpWidth; + //Width = tmpWidth; + //} + LocalPosition = new Vector2(value, LocalPosition.Y); + } + } + + /// + /// If @ClampedToParent is true will not set value beyond parent + /// + public double Bottom + { + get + { + return LocalPosition.Y + Size.Y; + } + } + + /// + /// If @ClampedToParent is true will not set value beyond parent + /// + public double Right + { + get + { + return LocalPosition.X + Size.X; + } + } + public virtual double Width + { + get + { + return Size.X; + } + set + { + Size = new Vector2(value, Size.Y); + } + } + + public virtual double Height + { + get + { + return Size.Y; + } + set + { + Size = new Vector2(Size.X, value); + } + } + public double GlobalLeft + { + get + { + return Position.X; + } + } + public double GlobalTop + { + get + { + return Position.Y; + } + } + } +} diff --git a/src/EPPlus.Graphics/BoundingBoxContainer.cs b/src/EPPlus.Graphics/BoundingBoxContainer.cs new file mode 100644 index 0000000000..b9dc361b74 --- /dev/null +++ b/src/EPPlus.Graphics/BoundingBoxContainer.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Graphics +{ + internal class BoundingBoxContainer : BoundingBox + { + internal double MarginLeft + { + get + { + return InnerBounds.Left; + } + set + { + InnerBounds.Left = value; + } + } + + internal double MarginTop + { + get + { + return InnerBounds.Top; + } + set + { + InnerBounds.Top = value; + } + } + + internal double MarginRight + { + get + { + return GetInnerRight(); + } + set + { + InnerBounds.Width = Width - value; + } + } + internal double MarginBottom + { + get + { + return GetInnerBottom(); + } + set + { + InnerBounds.Height = Height - value; + } + } + + BoundingBox InnerBounds; + + internal BoundingBoxContainer(BoundingBox innerBounds) : base() + { + InnerBounds = innerBounds; + } + + //internal BoundingBoxContainer(double l, double t, double r, double b) : base(l, t, r, b) + //{ + //} + + internal double GetInnerLeft() + { + return Left + MarginLeft; + } + + internal double GetInnerTop() + { + return Top + MarginTop; + } + + internal double GetInnerBottom() + { + return Bottom - MarginBottom; + } + + internal double GetInnerRight() + { + return Right - MarginRight; + } + + //public BoundingBox GetInnerBounds() + //{ + // var textArea = new BoundingBox(); + // textArea.Left = GetInnerLeft(); + // textArea.Top = GetInnerTop(); + + // textArea.Width = GetInnerWidth(); + // textArea.Height = GetInnerHeight(); + + // return textArea; + //} + + public double GetInnerWidth() + { + return GetInnerRight() - GetInnerLeft(); + } + + public double GetInnerHeight() + { + return GetInnerBottom() - GetInnerTop(); + } + } +} diff --git a/src/EPPlus.Graphics/EPPlus.Graphics.csproj b/src/EPPlus.Graphics/EPPlus.Graphics.csproj new file mode 100644 index 0000000000..70167ea1c8 --- /dev/null +++ b/src/EPPlus.Graphics/EPPlus.Graphics.csproj @@ -0,0 +1,71 @@ + + + + net8.0;net9.0;netstandard2.1;netstandard2.0;net462 + disable + disable + True + latest + EPPlus.Graphics.snk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPPlus.Graphics/EPPlus.Graphics.snk b/src/EPPlus.Graphics/EPPlus.Graphics.snk new file mode 100644 index 0000000000..bff237655d Binary files /dev/null and b/src/EPPlus.Graphics/EPPlus.Graphics.snk differ diff --git a/src/EPPlus.Graphics/Geometry/Matrix3x3.cs b/src/EPPlus.Graphics/Geometry/Matrix3x3.cs new file mode 100644 index 0000000000..588edc4db3 --- /dev/null +++ b/src/EPPlus.Graphics/Geometry/Matrix3x3.cs @@ -0,0 +1,137 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace EPPlus.Graphics.Geometry +{ + /// + /// Column Major Order 3x3 Matrix + /// + public class Matrix3x3 + { + public double A = 0d; + public double B = 0d; + public double C = 0d; + public double D = 0d; + public double E = 0d; + public double F = 0d; + public double G = 0d; + public double H = 0d; + public double I = 0d; + + public static Matrix3x3 Identity => new Matrix3x3(1,0,0, 1,0,0, 0,0,1); + + /// + /// Creates matrix + /// [a b 0] + /// [c d 0] + /// [e f 1] + /// + public Matrix3x3(double A, double B, double C, double D, double E, double F) + { + this.A = A; + this.B = B; + this.C = C; + this.D = D; + this.E = E; + this.F = F; + G = 0; + H = 0; + I = 1; + } + + public Matrix3x3(double A, double B, double C, double D, double E, double F, double G, double H, double I) + { + this.A = A; + this.B = B; + this.C = C; + this.D = D; + this.E = E; + this.F = F; + this.G = G; + this.H = H; + this.I = I; + } + + public static Matrix3x3 Invert(Matrix3x3 m) => m.Inverse(); + + public Matrix3x3 Inverse() + { + double[][] matrix = new double[3][] + { + new double[] { A, B, G }, + new double[] { C, D, H }, + new double[] { E, F, I } + }; + var inverse = MatrixHelper.Inverse(matrix); + return new Matrix3x3( + inverse[0][0], inverse[0][1], + inverse[1][0], inverse[1][1], + inverse[2][0], inverse[2][1], + inverse[0][2], inverse[1][2], inverse[2][2] + ); + } + + public static Matrix3x3 Translation(double tX, double tY) => new Matrix3x3(1, 0, 0, 1, tX, tY); + + public static Matrix3x3 Scaling(double sX, double sY) => new Matrix3x3(sX, 0, 0, sY, 0, 0); + + public static Matrix3x3 Rotation(double angleDegrees) + { + double radians = angleDegrees * System.Math.PI / 180d; + double cos = System.Math.Cos(radians); + double sin = System.Math.Sin(radians); + return new Matrix3x3(cos, sin, -sin, cos, 0, 0); + } + + public Vector2 Transform(Vector2 p) + { + return new Vector2( + A * p.X + B * p.Y + E, + C * p.X + D * p.Y + F + ); + } + + public static Matrix3x3 operator* (Matrix3x3 M1, Matrix3x3 M2) + { + double[][] a = new double[3][] + { + new double[] { M1.A, M1.B, M1.G }, + new double[] { M1.C, M1.D, M1.H }, + new double[] { M1.E, M1.F, M1.I } + }; + double[][] b = new double[3][] + { + new double[] { M2.A, M2.B, M2.G }, + new double[] { M2.C, M2.D, M2.H }, + new double[] { M2.E, M2.F, M2.I } + }; + var result = MatrixHelper.Multiply(a, b); + return new Matrix3x3 + ( + result[0][0], result[0][1], + result[1][0], result[1][1], + result[2][0], result[2][1], + result[0][2], result[1][2], result[2][2] + ); + } + + public static Vector2 operator* ( Vector2 V, Matrix3x3 M) + { + return new Vector2 + ( + M.A * V.X + M.C * V.Y + M.E, + M.B * V.X + M.D * V.Y + M.F + ); + } + } +} diff --git a/src/EPPlus.Graphics/Geometry/MatrixHelper.cs b/src/EPPlus.Graphics/Geometry/MatrixHelper.cs new file mode 100644 index 0000000000..5a947570c8 --- /dev/null +++ b/src/EPPlus.Graphics/Geometry/MatrixHelper.cs @@ -0,0 +1,507 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com +************************************************************************************************* + Date Author Change +************************************************************************************************* + 05/07/2023 EPPlus Software AB Implemented function +*************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Graphics.Geometry +{ + internal static class MatrixHelper + { + + //Contains various functions for matrix operations. + + internal static double[][] TransposeMatrix(double[][] matrix, int rows, int cols) + { + //This function takes a jagged matrix as input, and returns its transpose. + double[][] transposedMat = CreateMatrix(cols, rows); + + for (int r = 0; r < rows; r++) + { + for (int c = 0; c < cols; c++) + { + transposedMat[c][r] = matrix[r][c]; + } + } + return transposedMat; + } + + internal static double[][] MatrixMultDouble(double[][] matrix, double multiplier) + { + //Multiplies all elements in a matrix with a single number. + double[][] resultMat = CreateMatrix(matrix.Count(), matrix[0].Count()); + for (int row = 0; row < matrix.Count(); row++) + { + for (int col = 0; col < matrix[0].Count(); col++) + { + resultMat[row][col] = matrix[row][col] * multiplier; + } + } + return resultMat; + } + internal static double[] MatrixDiagonal(double[][] matrix) + { + //Returns the diagonal of a matrix. + double[] resultArray = new double[matrix.Count()]; + for (int row = 0; row < matrix[0].Count(); row++) + { + for (int col = 0; col < matrix.Count(); col++) + { + if (row == col) resultArray[row] = matrix[row][col]; + } + } + return resultArray; + } + + internal static double[][] CreateMatrix(int rows, int cols) + { + double[][] matrix = new double[rows][]; + for (int i = 0; i < rows; i++) + { + matrix[i] = new double[cols]; + } + return matrix; + } + + internal static double[][] Multiply(double[][] a, double[][] b) + { + int aY = a.Length; + int aX = a[0].Length; + int bY = b.Length; + int bX = b[0].Length; + if (aX != bY) + { + return null; + } + double[][] matrix = CreateMatrix(aY, bX); + for (int i = 0; i < aY; i++) + { + for (int j = 0; j < bX; j++) + { + for (int k = 0; k < aX; k++) + { + matrix[i][j] += a[i][k] * b[k][j]; + } + } + } + return matrix; + } + + internal static double[][] GetIdentityMatrix(int size) + { + double[][] identity = CreateMatrix(size, size); + for (int i = 0; i < size; i++) + { + identity[i][i] = 1.0d; + } + return identity; + } + + internal static double GetDeterminant(double[][] matrix) + { + int[] permutations; + int rowSwap; + double[][] lu = Decompose(matrix, out permutations, out rowSwap); + if (lu == null) return double.NaN; + double result = rowSwap; + for (int i = 0; i < lu.Length; ++i) + { + result *= lu[i][i]; + } + return result; + } + + internal static double GetDeterminant(double[][] lu, int rowSwap) + { + if (lu == null) return double.NaN; + double result = rowSwap; + for (int i = 0; i < lu.Length; ++i) + { + result *= lu[i][i]; + } + return result; + } + + internal static double[][] Decompose(double[][] matrix, out int[] permutations, out int rowSwap) + { + int rows = matrix.Length; + int cols = matrix[0].Length; + double[][] decomposedMatrix = Duplicate(matrix); + permutations = new int[rows]; + for (int i = 0; i < rows; i++) + { + permutations[i] = i; + } + rowSwap = 1; + for (int i = 0; i < rows - 1; i++) + { + double maxCols = System.Math.Abs(decomposedMatrix[i][i]); + int permRow = i; + for (int j = i + 1; j < rows; j++) + { + if (System.Math.Abs(decomposedMatrix[j][i]) > maxCols) + { + maxCols = System.Math.Abs(decomposedMatrix[j][i]); + permRow = j; + } + } + if (permRow != i) + { + double[] swapRow = decomposedMatrix[permRow]; + decomposedMatrix[permRow] = decomposedMatrix[i]; + decomposedMatrix[i] = swapRow; + int swap = permutations[permRow]; + permutations[permRow] = permutations[i]; + permutations[i] = swap; + rowSwap = -rowSwap; + } + if (decomposedMatrix[i][i] == 0.0) + { + int swapRowIndex = -1; + for (int row = i + 1; row < rows; row++) + { + if (decomposedMatrix[row][i] != 0.0) + swapRowIndex = row; + } + if (swapRowIndex == -1) return null; + double[] swapRow = decomposedMatrix[swapRowIndex]; + decomposedMatrix[swapRowIndex] = decomposedMatrix[i]; + decomposedMatrix[i] = swapRow; + int swap = permutations[swapRowIndex]; + permutations[swapRowIndex] = permutations[i]; + permutations[i] = swap; + rowSwap = -rowSwap; + } + for (int j = i + 1; j < rows; j++) + { + decomposedMatrix[j][i] /= decomposedMatrix[i][i]; + for (int k = i + 1; k < rows; k++) + { + decomposedMatrix[j][k] -= decomposedMatrix[j][i] * decomposedMatrix[i][k]; + } + } + } + return decomposedMatrix; + } + + internal static double[][] Duplicate(double[][] matrix) + { + var duplicate = new double[matrix.Length][]; + for (int i = 0; i < matrix.Length; i++) + { + var row = matrix[i]; + var newRow = new double[row.Length]; + Array.Copy(row, newRow, row.Length); + duplicate[i] = newRow; + } + return duplicate; + } + + internal static double[][] Inverse(double[][] matrix) + { + double[][] inverse = Duplicate(matrix); + double[][] lu = Decompose(matrix, out int[] permutations, out int rowSwap); + if (lu == null) return null; + double[] unit = new double[matrix.Length]; + for (int i = 0; i < matrix.Length; i++) + { + for (int j = 0; j < matrix.Length; j++) + { + if (i == permutations[j]) + { + unit[j] = 1.0; + } + else + { + unit[j] = 0.0; + } + } + double[] element = InverserSolver(lu, unit); + for (int j = 0; j < matrix.Length; j++) + { + inverse[j][i] = element[j]; + } + } + return inverse; + } + + internal static double[][] Inverse(double[][] lu, int[] permutations, int rowSwap) + { + double[][] inverse = Duplicate(lu); + if (lu == null) return null; + double[] unit = new double[lu.Length]; + for (int i = 0; i < lu.Length; i++) + { + for (int j = 0; j < lu.Length; j++) + { + if (i == permutations[j]) + { + unit[j] = 1.0; + } + else + { + unit[j] = 0.0; + } + } + double[] elements = InverserSolver(lu, unit); + for (int j = 0; j < lu.Length; j++) + { + inverse[j][i] = elements[j]; + } + } + return inverse; + } + + private static double[] InverserSolver(double[][] luMatrix, double[] unit) + { + double[] elements = new double[luMatrix.Length]; + unit.CopyTo(elements, 0); + for (int i = 1; i < luMatrix.Length; i++) + { + double product = elements[i]; + for (int j = 0; j < i; j++) + { + product -= luMatrix[i][j] * elements[j]; + } + elements[i] = product; + } + elements[luMatrix.Length - 1] /= luMatrix[luMatrix.Length - 1][luMatrix.Length - 1]; + for (int i = luMatrix.Length - 2; i >= 0; i--) + { + double product = elements[i]; + for (int j = i + 1; j < luMatrix.Length; j++) + { + product -= luMatrix[i][j] * elements[j]; + } + elements[i] = product / luMatrix[i][i]; + } + return elements; + } + + internal static int ArgMaxIndex(double[][] mat) + { + //This function finds the index of the largest absolute value in the input matrix + + double maxAbsValue = double.MinValue; + int maxIndex = -1; + int flatIndex = 0; + + for (int i = 0; i < mat.Count(); i++) + { + for (int j = 0; j < mat[0].Count(); j++) + { + double absValue = Math.Abs(mat[i][j]); + if (absValue > maxAbsValue) + { + maxAbsValue = absValue; + maxIndex = flatIndex; + } + flatIndex += 1; + } + } + + return maxIndex; + } + + internal static double GetM2Norm(double[][] rr) + { + + //Calculates the 2-norm (euclidean, L2 norm) of the matrix. + + int m = rr.Count(); + int n = rr[0].Count(); + + var m1norm = 0d; + for (int i = 0; i < n; i++) + { + //Sum of the max absolute values of all values in column i + var dd = 0d; + for (int r = 0; r < rr.Count(); r++) + { + dd += Math.Abs(rr[r][i]); + m1norm = Math.Max(m1norm, dd); + } + } + + var m8norm = 0d; + for (int i = 0; i < m; i++) + { + //Sum of the max absolute values of all values in row i + var dd = 0d; + for (int c = 0; c < rr[0].Count(); c++) + { + dd += Math.Abs(rr[i][c]); + m8norm = Math.Max(m8norm, dd); + } + } + + return Math.Sqrt(m1norm * m8norm); + } + + internal static List GaussRank(double[][] xRange, bool constVal) + { + //This function takes the input matrix and transforms it to echelon form (every leading coefficient is 1 and is to the right of the leading coefficient on the row above). + //This is done with complete pivoting to improve numerical stability and identify linearly dependent columns. + // + var xTdotX = MatrixHelper.Multiply(MatrixHelper.TransposeMatrix(xRange, xRange.Count(), xRange[0].Count()), xRange); + List drop = new List(); + int m = xTdotX.Length; + int n = xTdotX[0].Length; + var m2norm = GetM2Norm(xRange); + var eps = 2.220446049250313E-16; + var xeps = 1000 * eps; + int ixr; + int ixc; + + double[] colOrder = new double[n]; + int count = 0; + for (int i = 0; i < n; i++) + { + colOrder[i] = count; + count += 1; + } + + for (int ix0 = 0; ix0 < n; ix0++) + { + if (ix0 == 0 && constVal) + { + //If column with 1's has been added, this column is addressed first. + ixr = 0; + ixc = 0; + } + else + { + //Complete pivoting is performed + //Pivote element becomes the index with the largest absolute value in each sub matrix + double[][] subMatrix = new double[m - ix0][]; + int rowCount = 0; + for (int i = ix0; i < m; i++) + { + subMatrix[rowCount] = new double[n - ix0]; + int colCount = 0; + for (int j = ix0; j < n; j++) + { + subMatrix[rowCount][colCount] = xTdotX[i][j]; + colCount += 1; + } + rowCount += 1; + } + int dd = ArgMaxIndex(subMatrix); + + ixr = dd / (n - ix0); + ixc = dd % (n - ix0); + ixr += ix0; + ixc += ix0; + + List ddArray = new List(); + for (int i = 0; i < xTdotX[ixr].Count(); i++) + { + var tmp = Math.Abs(Math.Abs(xTdotX[ixr][i]) - Math.Abs(xTdotX[ixr][ixc])); + if (tmp < 1000 * xeps) ddArray.Add(i); + } + ixc = (int)ddArray[0]; + if (ddArray.Count() > 1) + { + ixc = (int)ddArray[ddArray.Count() - 1]; + } + } + + if (Math.Abs(xTdotX[ixr][ixc]) > eps) + { + //row swap + for (int i = 0; i < xTdotX[ixr].Count(); ++i) + { + var tmp = xTdotX[ix0][i]; + xTdotX[ix0][i] = xTdotX[ixr][i]; + xTdotX[ixr][i] = tmp; + } + //column swap + for (int i = 0; i < xTdotX.Count(); i++) + { + var tmp = xTdotX[i][ix0]; + xTdotX[i][ix0] = xTdotX[i][ixc]; + xTdotX[i][ixc] = tmp; + } + + var tmp1 = colOrder[ix0]; + colOrder[ix0] = colOrder[ixc]; + colOrder[ixc] = tmp1; + + //Elimination + for (int ix2 = ix0 + 1; ix2 < m; ix2++) + { + var dd = xTdotX[ix2][ix0] / xTdotX[ix0][ix0]; + + for (int j = 0; j < xTdotX[ix2].Count(); j++) + { + xTdotX[ix2][j] -= xTdotX[ix0][j] * dd; + } + } + + } + } + + //Deciding on collinear columns: + for (int i = 0; i < n; i++) + { + var v1 = xTdotX[i][i]; + var v2 = m2norm; + var v3 = xeps; + var v4 = Math.Floor(Math.Abs(v1 / v2) / v3); //.Floor should be correct + if (v4 == 0) + { + drop.Add(colOrder[i]); + } + } + + //Contains column index on what variables should be dropped due to collinearity + return drop; + } + + internal static double[][] RemoveColumns(double[][] xRangeList, List dropCols) + { + //Removes column indexes in dropCols from the matrix xRangeList + int height = xRangeList.Length; + if (height == 0) return xRangeList; + + int width = xRangeList[0].Length; + HashSet dropColsSet = new HashSet(dropCols); + + double[][] newXRangeList = new double[height][]; + for (int i = 0; i < height; i++) + { + List newRow = new List(); + for (int j = 0; j < width; j++) + { + if (!dropColsSet.Contains(j)) + { + newRow.Add(xRangeList[i][j]); + } + } + newXRangeList[i] = newRow.ToArray(); + } + + return newXRangeList; + } + + internal static double[] ListToArray(List list) + { + double[] arr = new double[list.Count]; + for (var i = 0; i < list.Count; i++) + { + arr[i] = list[i]; + } + return arr; + } + } +} diff --git a/src/EPPlus.Graphics/Geometry/Vector2.cs b/src/EPPlus.Graphics/Geometry/Vector2.cs new file mode 100644 index 0000000000..8aac7f2f96 --- /dev/null +++ b/src/EPPlus.Graphics/Geometry/Vector2.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace EPPlus.Graphics.Geometry +{ + /// + /// This should REMAIN a struct + /// Several math operations and the structure of parent-child hierarchy + /// RELIES on that assumption. + /// As a class Zero and One can have x and y assigned to and this creates chaos as they should be constant + /// + public struct Vector2 + { + public double X { get; set; } = 0; + public double Y { get; set; } = 0; + + public const double Z = 1; //Z is always 1 in pdf. + + public double Length + { + get { return System.Math.Sqrt(X * X + Y * Y); } + } + + public double LengthSquared + { + get { return X * X + Y * Y; } + } + + public Vector2() { } + + public Vector2(double x, double y) + { + X = x; + Y = y; + } + + public static readonly Vector2 Zero = new Vector2(0, 0); + public static readonly Vector2 One = new Vector2(1, 1); + + public static Vector2 operator +(Vector2 v1, Vector2 v2) => new Vector2(v1.X + v2.X, v1.Y + v2.Y); + public static Vector2 operator -(Vector2 v1, Vector2 v2) => new Vector2(v1.X - v2.X, v1.Y - v2.Y); + public static Vector2 operator *(Vector2 v, double s) => new Vector2(v.X * s, v.Y * s); + public static Vector2 operator *(double s, Vector2 v) => v * s; + public static Vector2 operator *(Vector2 v1, Vector2 v2) => new Vector2(v1.X * v2.X, v1.Y * v2.Y); + public static Vector2 operator /(Vector2 v1, Vector2 v2) => new Vector2(v1.X / v2.X, v1.Y / v2.Y); + public static Vector2 operator /(Vector2 v, double s) => new Vector2(v.X / s, v.Y / s); + public static double Dot(Vector2 v1, Vector2 v2) + { + return v1.X * v2.X + v1.Y * v2.Y; + } + public static Vector2 Project(Vector2 vector, Vector2 onto) + { + double length = onto.LengthSquared; + if (length == 0) return new Vector2(0, 0); + double scale = Dot(vector, onto) / length; + return new Vector2(onto.X * scale, onto.Y * scale); + } + } +} diff --git a/src/EPPlus.Graphics/Point.cs b/src/EPPlus.Graphics/Point.cs new file mode 100644 index 0000000000..3e5d032350 --- /dev/null +++ b/src/EPPlus.Graphics/Point.cs @@ -0,0 +1,40 @@ +using EPPlus.Graphics.Geometry; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Graphics +{ + public class Point : Transform + { + public double Top + { + get { return LocalPosition.Y; } + set + { + LocalPosition = new Vector2(LocalPosition.X, value); + } + } + + public double Left + { + get { return LocalPosition.X; } + set + { + LocalPosition = new Vector2(value, LocalPosition.Y); + } + } + + public Point() + { + + } + + public Point(double x, double y) + { + Left = x; + Top = y; + } + } +} diff --git a/src/EPPlus.Graphics/Rect.cs b/src/EPPlus.Graphics/Rect.cs new file mode 100644 index 0000000000..fe5a1d4b5f --- /dev/null +++ b/src/EPPlus.Graphics/Rect.cs @@ -0,0 +1,102 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics.Geometry; + +namespace EPPlus.Graphics +{ + //REname and move class? Inherit from Transform? what do? + public class Rect + { + + public Rect() + { + } + + public Rect(double width, double height) : this() + { + Left = 0; + Top = 0; + Right = width; + Bottom = height; + } + public Rect(double left, double top, double right, double bottom) : this() + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + /// + /// Y pos (min) + /// + public virtual double Top { get; set; } + + /// + /// Y pos (max) + /// + public virtual double Bottom { get; set; } + + /// + /// X pos (min) + /// + public virtual double Left { get; set; } + + /// + /// X pos (max) + /// + public virtual double Right { get; set; } + + /// + /// Get or Set Width via the properties above + /// + public virtual double Width + { + get + { + return Right - Left; + } + set + { + Right = Left + value; + } + } + + /// + /// Gets or sets height via the properties above + /// + public virtual double Height + { + get + { + return Bottom - Top; + } + set + { + Bottom = Top + value; + } + } + + /// + /// Local position X + /// X-position from parent Transform position + /// + public double X; + + /// + /// Local position Y + /// Y-position from parent Transform position + /// + public double Y; + } +} diff --git a/src/EPPlus.Graphics/RectBase.cs b/src/EPPlus.Graphics/RectBase.cs new file mode 100644 index 0000000000..7a368b6e91 --- /dev/null +++ b/src/EPPlus.Graphics/RectBase.cs @@ -0,0 +1,53 @@ +namespace EPPlus.Graphics +{ + public class RectBase + { + public double Left { get; set; } + internal double Top { get; set; } + public double Right { get; set; } + public double Bottom { get; set; } + + public RectBase() + { + } + + public RectBase(double width, double height) + { + Left = 0; + Top = 0; + Right = width; + Bottom = height; + } + public RectBase(double left, double top, double right, double bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + public double Width + { + get + { + return Right - Left; + } + set + { + Right = Left + value; + } + } + + public double Height + { + get + { + return Bottom - Top; + } + set + { + Bottom = Top + value; + } + } + } +} diff --git a/src/EPPlus.Graphics/RectMargins.cs b/src/EPPlus.Graphics/RectMargins.cs new file mode 100644 index 0000000000..6bf97e310e --- /dev/null +++ b/src/EPPlus.Graphics/RectMargins.cs @@ -0,0 +1,64 @@ +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Graphics +{ + public class RectMargins : Rect + { + public double MarginLeft { get; set; } + public double MarginTop { get; set; } + public double MarginRight { get; set; } + public double MarginBottom { get; set; } + + public RectMargins() : base() { } + + public RectMargins(double l, double t, double r, double b) : base(l, t, r, b) + { + } + + public double GetInnerLeft() + { + return Left + MarginLeft; + } + + public double GetInnerTop() + { + return Top + MarginTop; + } + + public double GetInnerBottom() + { + return Bottom - MarginBottom; + } + + public double GetInnerRight() + { + return Right - MarginRight; + } + + public RectBase GetInnerRect() + { + var textArea = new RectBase(); + textArea.Left = GetInnerLeft(); + textArea.Top = GetInnerTop(); + + textArea.Bottom = GetInnerBottom(); + textArea.Right = GetInnerRight(); + + return textArea; + } + + public double GetInnerWidth() + { + return GetInnerRight() - GetInnerLeft(); + } + + public double GetInnerHeight() + { + return GetInnerBottom() - GetInnerTop(); + } + } +} diff --git a/src/EPPlus.Graphics/Transform.cs b/src/EPPlus.Graphics/Transform.cs new file mode 100644 index 0000000000..1e56b96c41 --- /dev/null +++ b/src/EPPlus.Graphics/Transform.cs @@ -0,0 +1,366 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Globalization; +using EPPlus.Graphics.Geometry; + +namespace EPPlus.Graphics +{ + public class Transform + { + public string Name; + + public Vector2 LocalPosition { get; set; } = Vector2.Zero; + + public Vector2 GetWorldCoordinates() + { + return TransformPointToWorld(Vector2.Zero); + } + + public void SetLocalPositionWithWorldCoordinates(Vector2 worldPosCoords) + { + if (Parent == null) + { + LocalPosition = worldPosCoords; + } + else + { + LocalPosition = worldPosCoords * Parent.GetWorldMatrix().Inverse(); + } + } + + /// + /// Gets a copied vector of the local position in world coordinates + /// Sets the local position variable using a vector2 in world coordinates + /// + public Vector2 Position + { + get + { + return TransformPointToWorld(Vector2.Zero); + } + set + { + if (Parent == null) + { + LocalPosition = value; + } + else + { + LocalPosition = value * Parent.GetWorldMatrix().Inverse(); + } + } + } + + //public Vector2 Position + //{ + // get + // { + // if (Parent == null) + // { + // return LocalPosition; + // } + // else + // { + // return TransformPointToWorld(Vector2.Zero); + // } + // } + // set + // { + // if (Parent == null) + // { + // LocalPosition = value; + // } + // else + // { + // LocalPosition = value * Parent.GetWorldMatrix().Inverse(); + // } + // } + //} + + + public Vector2 LocalScale { get; set; } = Vector2.One; + + public Vector2 Scale + { + get + { + if (Parent == null) + return LocalScale; + else + return Parent.Scale * LocalScale; + } + set + { + if (Parent == null) + { + LocalScale = value; + } + else + { + LocalScale = value / Parent.Scale; + } + } + } + + public double LocalRotationRadians => LocalRotation * System.Math.PI / 180.0; + + private double localRotationDegrees = 0; + + public double LocalRotation + { + get + { + return localRotationDegrees; + } + set + { + localRotationDegrees = value; + } + } + + public double RotationRadians => Rotation * System.Math.PI / 180.0; + + public double Rotation + { + get + { + return Parent != null ? Parent.Rotation + LocalRotation : LocalRotation; + } + set + { + if (Parent != null) + LocalRotation = value - Parent.Rotation; + else + LocalRotation = value; + } + } + + public Vector2 Size { get; set; } = Vector2.Zero; + + public int Z { get; set; } = 0; + + private Transform _parent = null; + public Transform Parent + { + get + { + return _parent; + } + set + { + if (_parent == value) return; + if (_parent != null) + { + _parent.RemoveChild(this); + } + if (value != null) + { + value.AddChild(this); + } + else + { + _parent = null; + } + } + } + + private List _childObjects = null; + public List ChildObjects + { + get + { + if (_childObjects == null) + { + _childObjects = new List(); + } + return _childObjects; + } + set + { + if (_childObjects == null) + { + _childObjects = new List(); + } + } + } + + public Transform() { } + + public Transform(Vector2 position, Vector2 size) + : this(position, size, Vector2.One, 0d, null) { } + + public Transform(Vector2 position, Vector2 size, Vector2 scale) + : this(position, size, scale, 0d, null) { } + + public Transform(Vector2 position, Vector2 size, Vector2 scale, double rotation) + : this(position, size, scale, rotation, null) { } + + public Transform(Vector2 position, Vector2 size, Transform parent) + : this(position, size, Vector2.One, 0d, parent) { } + + public Transform(Vector2 position, Vector2 size, Vector2 scale, Transform parent) + : this(position, size, scale, 0d, parent) { } + + public Transform(Vector2 position, Vector2 size, Vector2 scale, double rotation, Transform parent) + { + Position = position; + Size = size; + Scale = scale; + Rotation = rotation; + Parent = parent; + ChildObjects = null; + } + + public Transform(double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + { + Position = new Vector2(x, y); + Size = new Vector2(width, height); + Scale = new Vector2(scaleX, scaleY); + Rotation = rotation; + Parent = parent; + ChildObjects = null; + } + public Transform AddChild(Transform child) + { + Vector2 worldPos; + if(child.Parent != null) + { + worldPos = child.Position; + child.Parent.RemoveChild(child); + var parentInverse = GetWorldMatrix().Inverse(); + child.LocalPosition = worldPos * parentInverse; + } + if (!ChildObjects.Contains(child)) + { + ChildObjects.Add(child); + } + child._parent = this; + return child; + } + public Transform InsertChildAt(Transform child, int at) + { + Vector2 worldPos; + if (child.Parent != null) + { + worldPos = child.Position; + child.Parent.RemoveChild(child); + var parentInverse = GetWorldMatrix().Inverse(); + child.LocalPosition = worldPos * parentInverse; + } + if (!ChildObjects.Contains(child)) + { + ChildObjects.Insert(at, child); + } + child._parent = this; + return child; + } + + public void RemoveChild(Transform child) + { + if (child == null) return; + if(ChildObjects.Remove(child)) + { + child._parent = null; + } + } + + public void Translate(Vector2 offset) + { + LocalPosition += offset; + } + public void Translate(double x, double y) + { + Translate(new Vector2(x, y)); + } + + public Vector2 TransformPointToLocal(Vector2 point) + { + return point * GetWorldMatrix().Inverse(); + } + + public Vector2 TransformPointToWorld(Vector2 point) + { + return point * GetWorldMatrix(); + } + + public Matrix3x3 GetLocalMatrix() + { + var scale = Matrix3x3.Scaling(LocalScale.X, LocalScale.Y); + var rotation = Matrix3x3.Rotation(LocalRotation); + var translation = Matrix3x3.Translation(LocalPosition.X, LocalPosition.Y); + return scale * rotation * translation; + } + + public Matrix3x3 GetWorldMatrix() + { + return Parent != null ? GetLocalMatrix() * Parent.GetWorldMatrix() : GetLocalMatrix(); + } + + public Rect GetGlobalBoundingbox() + { + var worldMatrix = GetWorldMatrix(); + var corners = new[] { new Vector2(0, 0), new Vector2(Size.X, 0), new Vector2(0, Size.Y), new Vector2(Size.X, Size.Y) }.Select(p => p * worldMatrix); + var minX = corners.Min(p => p.X); + var minY = corners.Min(p => p.Y); + var maxX = corners.Max(p => p.X); + var maxY = corners.Max(p => p.Y); + var rect = new Rect(); + rect.Left = minX; + rect.Top = minY; + rect.Right = maxX; + rect.Bottom = maxY; + return rect; + } + + public static bool Intersects(Rect bbox, Rect pageBounds) + { + return !(bbox.Right < pageBounds.Left || + bbox.Left > pageBounds.Right || + bbox.Bottom < pageBounds.Top || + bbox.Top > pageBounds.Bottom ); + } + + public static bool IntersectsFully(Rect contentBounds, Rect cellBounds) + { + var l1 = System.Math.Round(contentBounds.Left, 4); + var l2 = System.Math.Round(cellBounds.Left, 4); + var t1 = System.Math.Round(contentBounds.Top, 4); + var t2 = System.Math.Round(cellBounds.Top, 4); + var r1 = System.Math.Round(contentBounds.Right, 4); + var r2 = System.Math.Round(cellBounds.Right, 4); + var b1 = System.Math.Round(contentBounds.Bottom, 4); + var b2 = System.Math.Round(cellBounds.Bottom, 4); + + return l2 >= l1 && + t2 >= t1 && + r2 <= r1 && + b2 <= b1; + } + + public string ToHierarchyString(int indentLevel = 0) + { + var indent = new string(' ', indentLevel * 4); + var result = $"{indent}{Name ?? GetType().Name}|" + + $"({LocalPosition.X.ToString(CultureInfo.InvariantCulture)},{LocalPosition.Y.ToString(CultureInfo.InvariantCulture)}):" + + $"({Size.X.ToString(CultureInfo.InvariantCulture)},{Size.Y.ToString(CultureInfo.InvariantCulture)})"; + foreach (var child in ChildObjects) + { + result += Environment.NewLine + child.ToHierarchyString(indentLevel + 1); + } + return result; + } + } +} diff --git a/src/EPPlus.Graphics/Units/UnitConversion.cs b/src/EPPlus.Graphics/Units/UnitConversion.cs new file mode 100644 index 0000000000..f13e067581 --- /dev/null +++ b/src/EPPlus.Graphics/Units/UnitConversion.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Graphics.Units +{ + public static class UnitConversion + { + public const double PointsPerInch = 72.0d; + public const double MmPerInch = 25.4d; + public const double DPI = 600d; + + public static double MmToPoints(double mm) + { + return mm * PointsPerInch / MmPerInch; + } + + public static double PointsToMm(double points) + { + return points * MmPerInch / PointsPerInch; + } + + public static int MmToPointsRounded(double mm) + { + return (int)System.Math.Round(MmToPoints(mm)); + } + + public static int PointsToMmRounded(double points) + { + return (int)System.Math.Round(PointsToMm(points)); + } + + public static double ExcelPointsToMM(double excelPoints) + { + return excelPoints * (1 / PointsPerInch*10); + } + + public static double ExcelColumnWidthToPoints(double columnWidth, double char0) + { + return columnWidth * char0 + 0.75d; + } + + public static double ExcelRowHeightToPoints(double rowHeight) + { + return rowHeight; //These values are guessed. + } + } +} diff --git a/src/EPPlus.Interfaces/Drawing/Text/MeasurementFont.cs b/src/EPPlus.Interfaces/Drawing/Text/MeasurementFont.cs index 0b715f3df8..8e49c99de2 100644 --- a/src/EPPlus.Interfaces/Drawing/Text/MeasurementFont.cs +++ b/src/EPPlus.Interfaces/Drawing/Text/MeasurementFont.cs @@ -11,6 +11,11 @@ Date Author Change 1/4/2021 EPPlus Software AB EPPlus Interfaces 1.0 *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + namespace OfficeOpenXml.Interfaces.Drawing.Text { public class MeasurementFont diff --git a/src/EPPlus.Interfaces/Drawing/Text/TextMeasurement.cs b/src/EPPlus.Interfaces/Drawing/Text/TextMeasurement.cs index 02680b9f26..a2b4e8dd84 100644 --- a/src/EPPlus.Interfaces/Drawing/Text/TextMeasurement.cs +++ b/src/EPPlus.Interfaces/Drawing/Text/TextMeasurement.cs @@ -31,6 +31,11 @@ public TextMeasurement(float width, float height) /// public float Height { get; set; } + /// + /// Height of Font without linespacing. + /// + public float FontHeight { get; set; } + public static TextMeasurement Empty { get { return new TextMeasurement(-1, -1); } diff --git a/src/EPPlus.Interfaces/EPPlus.Interfaces.csproj b/src/EPPlus.Interfaces/EPPlus.Interfaces.csproj index 2d1ad82d58..3a0158508a 100644 --- a/src/EPPlus.Interfaces/EPPlus.Interfaces.csproj +++ b/src/EPPlus.Interfaces/EPPlus.Interfaces.csproj @@ -1,6 +1,6 @@  - net10.0;net9.0;net8.0;netstandard2.1;netstandard2.0;net462;net35 + net10.0;net9.0;net8.0;netstandard2.1;netstandard2.0;net462 8.4.0.0 8.4.0.0 8.4.0 diff --git a/src/EPPlus.Interfaces/Fonts/FontAvailability.cs b/src/EPPlus.Interfaces/Fonts/FontAvailability.cs new file mode 100644 index 0000000000..213f632459 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/FontAvailability.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Result of a font availability check. + /// + public enum FontAvailability + { + /// The font family is not available on the system. + NotFound, + + /// The font family is available, but not in the requested subfamily + /// (e.g. Regular exists but Bold was requested). + FamilyOnly, + + /// The exact font family and subfamily is available. + Exact + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/FontSubFamily.cs b/src/EPPlus.Interfaces/Fonts/FontSubFamily.cs new file mode 100644 index 0000000000..9c5659cf5d --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/FontSubFamily.cs @@ -0,0 +1,22 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +namespace OfficeOpenXml.Interfaces.Fonts +{ + public enum FontSubFamily + { + Regular, + Bold, + Italic, + BoldItalic + } +} diff --git a/src/EPPlus.Interfaces/Fonts/GlyphWidth.cs b/src/EPPlus.Interfaces/Fonts/GlyphWidth.cs new file mode 100644 index 0000000000..9cbf5fd485 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/GlyphWidth.cs @@ -0,0 +1,56 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/24/2026 EPPlus Software AB Lightweight glyph for text measurement + *************************************************************************************************/ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Lightweight glyph representation optimized for text measurement and wrapping. + /// Contains only essential data needed for width calculations. + /// This struct is 8 bytes total - 85% smaller than ShapedGlyph class (56 bytes). + /// + [DebuggerDisplay("XAdvance: {XAdvance}, ClusterIndex: {ClusterIndex}, CharCount: {CharCount}")] + [StructLayout(LayoutKind.Sequential)] + public struct GlyphWidth + { + /// + /// Horizontal advance width in font units. + /// Includes kerning adjustments. + /// Max value: 65,535 font units (more than sufficient for any font). + /// + public ushort XAdvance; + + /// + /// Index of the original character(s) that produced this glyph. + /// Used to map glyph widths back to character positions. + /// For ligatures, this points to the first character. + /// Max value: 65,535 characters per string. + /// + public ushort ClusterIndex; + + /// + /// Number of characters consumed by this glyph. + /// 1 for normal glyphs, 2+ for ligatures (e.g., "fi" → 1 glyph, 2 chars). + /// Max value: 255 characters per ligature (more than sufficient). + /// + public byte CharCount; + + /// + /// Which font produced this glyph (0 = first used font, 1+ = fallbacks). + /// Needed for correct point conversion when fonts have different UnitsPerEm. + /// + public byte FontId; + + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/IEpplusFontConfiguration.cs b/src/EPPlus.Interfaces/Fonts/IEpplusFontConfiguration.cs new file mode 100644 index 0000000000..0aa862747f --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/IEpplusFontConfiguration.cs @@ -0,0 +1,86 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/27/2026 EPPlus Software AB Initial implementation + 05/06/2026 EPPlus Software AB Property-based transactional configuration + 05/20/2026 EPPlus Software AB Added per-script glyph fallback configuration + *************************************************************************************************/ +using System.Collections.Generic; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Per-workbook font configuration for EPPlus. + /// Accessed via ExcelWorkbook.ConfigureFonts(Action<IEpplusFontConfiguration>). + /// Changes made inside a ConfigureFonts callback are applied as a single transaction — + /// when the callback returns, the font resolver is rebuilt and the workbook's font caches are cleared. + /// + public interface IEpplusFontConfiguration + { + /// + /// Additional directories to search for font files, beyond the system font directories. + /// Mutate this list inside a Configure callback to add or remove search paths. + /// + IList FontDirectories { get; } + + /// + /// Whether the operating system's standard font directories should be searched. + /// Defaults to true. Set to false to restrict font resolution to the + /// directories listed in . + /// + bool SearchSystemDirectories { get; set; } + + /// + /// The font resolver responsible for producing raw TTF/OTF bytes for a requested font. + /// Set this to replace the default resolver entirely. When a custom resolver is set, + /// the EPPlus built-in fallback chains and Archivo Narrow ultimate fallback are bypassed — + /// the resolver is fully responsible for handling missing fonts. + /// + IFontResolver FontResolver { get; set; } + + /// + /// User-defined font-name fallback chains. + /// Each entry maps a font name to an ordered list of fallbacks to try when the primary + /// is unavailable. Mutate this dictionary inside a Configure callback to add or remove + /// chains. User chains are tried before the EPPlus built-in fallback chains. + /// + IDictionary FontFallbacks { get; } + + /// + /// Replaces the per-script glyph fallback chain for the given Unicode script. + /// When the primary font (and any font-level fallbacks) lack a glyph for a character + /// that belongs to , EPPlus walks this chain in order and + /// uses the first font that contains the glyph. + /// + /// Setting a chain via this method fully replaces the built-in default for that script. + /// The caller becomes responsible for providing a complete chain — there is no merge + /// with the default. Pass an empty array to disable fallback for the script entirely. + /// + /// Note: Emoji and Math glyphs are always served by EPPlus's bundled Noto Emoji and + /// Noto Math fonts respectively, regardless of this configuration. + /// + /// The Unicode script to configure. + /// Ordered list of font names to try. + void SetScriptFallback(UnicodeScript script, params string[] fallbackFontNames); + + /// + /// Restores all settings to factory defaults: + /// + /// Clears . + /// Sets to true. + /// Restores the default (with Archivo Narrow built-in fallback). + /// Clears . + /// Restores the default per-script glyph fallback chains. + /// + /// + void Reset(); + } + +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/IFontAvailabilityProvider.cs b/src/EPPlus.Interfaces/Fonts/IFontAvailabilityProvider.cs new file mode 100644 index 0000000000..c997f3926f --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/IFontAvailabilityProvider.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + *************************************************************************************************/ +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Optional capability for font resolvers that can report on font availability + /// without performing a full font load. Implement this on a custom + /// to support + /// OpenTypeFonts.GetFontAvailability(...) with full fidelity — including + /// distinguishing between an exact subfamily match and a family-only match. + /// + /// Resolvers that do not implement this interface still work; in that case + /// OpenTypeFonts.GetFontAvailability falls back to probing via + /// , which can only distinguish + /// "found" from "not found". + /// + public interface IFontAvailabilityProvider + { + /// + /// Checks whether the specified font is available, and at what level + /// of specificity. + /// + /// The font family name to check. + /// The requested subfamily (Regular, Bold, Italic, BoldItalic). + FontAvailability GetFontAvailability(string fontName, FontSubFamily subFamily); + } +} diff --git a/src/EPPlus.Interfaces/Fonts/IFontResolver.cs b/src/EPPlus.Interfaces/Fonts/IFontResolver.cs new file mode 100644 index 0000000000..9d71cb4ec8 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/IFontResolver.cs @@ -0,0 +1,31 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 + 02/26/2026 EPPlus Software AB Simplified to return raw font bytes + *************************************************************************************************/ +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Resolves a font by name and subfamily to raw font bytes. + /// Implement this interface to provide fonts from any source (file system, database, embedded resources, etc.). + /// Font format (TTF/OTF) is detected automatically from the returned bytes. + /// + public interface IFontResolver + { + /// + /// Resolves a font to its raw bytes. + /// + /// Font family name (e.g. "Roboto") + /// Font subfamily (Regular, Bold, Italic, etc.) + /// Raw font bytes, or null if the font could not be found + byte[] ResolveFont(string fontName, FontSubFamily subFamily); + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ITextShaper.cs b/src/EPPlus.Interfaces/Fonts/ITextShaper.cs new file mode 100644 index 0000000000..c8933f6413 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ITextShaper.cs @@ -0,0 +1,96 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Core text shaping - converts text to positioned glyphs. + /// Works in font design units only. + /// + public interface ITextShaper + { + /// + /// Shapes text applying OpenType features (ligatures, kerning, etc.). + /// Returns positioned glyphs in font design units. + /// + ShapedText Shape(string text, ShapingOptions options = null); + + /// + /// Shapes text into a lightweight result optimized for text measurement. + /// Returns containing structs + /// (8 bytes each) plus per-font UnitsPerEm for correct multi-font width calculation. + /// + ShapedLightText ShapeLight(string text, ShapingOptions options = null); + + /// + /// Shapes multiple lines (splits on CR/LF/CRLF and shapes each line). + /// Returns array of shaped lines in font design units. + /// + ShapedText[] ShapeLines(string text, ShapingOptions options = null); + + /// + /// Shapes text for vertical layout (top-to-bottom glyph stacking). + /// Used for Excel vertical text mode (text rotation value 255), where glyphs + /// are rendered upright and stacked vertically rather than laid out horizontally. + /// Advance heights are sourced from the 'vmtx' table when available, + /// with fallback to 'hmtx' advance widths for fonts without vertical metrics. + /// + /// Text to shape + /// Shaping options + /// Shaped vertical text with positioned glyphs in font design units + ShapedVerticalText ShapeVertical(string text, ShapingOptions options = null); + + /// + /// Shapes text for vertical layout into lightweight + /// structs optimized for vertical text measurement. + /// Analogous to for horizontal text. + /// Advance heights are sourced from the 'vmtx' table when available, + /// with fallback to 'hmtx' advance widths for fonts without vertical metrics. + /// + /// Text to shape + /// Shaping options + /// Array of lightweight vertical glyph height structs (8 bytes each) + VerticalGlyphHeight[] ShapeLightVertical(string text, ShapingOptions options = null); + + double[] ExtractCharWidths(string text, float fontSize, ShapingOptions options); + + void ExtractCharWidths(string text, float fontSize, ShapingOptions options, double[] targetArray); + + // === Font Metrics (in design units or converted to points) === + + /// + /// Gets single line spacing (baseline-to-baseline) in points. + /// + float GetLineHeightInPoints(float fontSize); + + /// + /// Gets total font height (ascent + descent) in points. + /// + float GetFontHeightInPoints(float fontSize); + + /// + /// Gets Ascent (top of container to the baseline) in points + /// + float GetAscentInPoints(float fontSize); + + /// + /// Gets descent distance (below baseline) in points. + /// + float GetDescentInPoints(float fontSize); + + /// + /// Gets the font's units per em (for manual conversions). + /// + ushort UnitsPerEm { get; } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapedGlyph.cs b/src/EPPlus.Interfaces/Fonts/ShapedGlyph.cs new file mode 100644 index 0000000000..fe05a6a18e --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapedGlyph.cs @@ -0,0 +1,165 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + 01/24/2026 EPPlus Software AB Optimized to struct (79% memory reduction) + 01/31/2026 EPPlus Software AB Added BaseAdvance for kerning optimization + *************************************************************************************************/ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Represents a shaped glyph with positioning information. + /// All measurements are in font units (not PDF points or pixels). + /// OPTIMIZED: Changed to struct for 79% memory reduction (56 bytes → 12 bytes). + /// + [DebuggerDisplay("GlyphId: {GlyphId}, XAdvance: {XAdvance}, BaseAdvance: {BaseAdvance}, CharCount: {CharCount}")] + public class ShapedGlyph + { + /// + /// The glyph ID in the font. + /// Range: 0-65,535 (ushort is sufficient for all fonts). + /// + public ushort GlyphId; + + /// + /// Horizontal advance width in font units INCLUDING kerning/positioning adjustments. + /// This is the actual advance to use for layout. + /// Signed to support negative kerning (rare but possible). + /// Range: -32,768 to +32,767 (sufficient for all practical fonts). + /// + public short XAdvance; + + /// + /// Original horizontal advance width from hmtx table (BEFORE kerning). + /// Used to calculate kerning: Kerning = XAdvance - BaseAdvance + /// This allows PDF rendering to write kerning adjustments without looking up hmtx. + /// Range: -32,768 to +32,767 (sufficient for all practical fonts). + /// + public short BaseAdvance; + + /// + /// Vertical advance height in font units. + /// Typically 0 for horizontal text. + /// Signed to support vertical text layouts. + /// + public short YAdvance; + + /// + /// Horizontal offset adjustment in font units. + /// Used for positioning marks, subscripts, superscripts. + /// Must be signed as offsets can be negative. + /// + public short XOffset; + + /// + /// Vertical offset adjustment in font units. + /// Used for positioning marks, subscripts, superscripts. + /// Must be signed as offsets can be negative. + /// + public short YOffset; + + /// + /// Index of the original character(s) that produced this glyph. + /// Used for text selection and editing. + /// For ligatures, this points to the first character. + /// Range: 0-65,535 characters per string (ushort is sufficient). + /// + public ushort ClusterIndex; + + /// + /// Number of characters consumed by this glyph. + /// 1 for normal glyphs, 2+ for ligatures (e.g., "fi" → 1 glyph, 2 chars). + /// Range: 0-255 characters per ligature (byte is more than sufficient). + /// + public byte CharCount; + + /// + /// Reserved byte for future use and perfect alignment. + /// + public byte Reserved; + + // Total size: 16 bytes (perfectly aligned for 64-bit systems) + // Previous version (without BaseAdvance): 14 bytes + // Memory cost: +2 bytes per glyph (+14% increase) + // Performance gain: 8-10x faster PDF kerning rendering + + /// + /// Gets the kerning adjustment applied to this glyph. + /// Positive = glyphs moved apart, Negative = glyphs moved closer. + /// + public short Kerning => (short)(XAdvance - BaseAdvance); + + /// + /// 0 = primary, 1+ = fallbacks + /// + public byte FontId { get; set; } + /// + /// Creates a new shaped glyph with specified glyph ID and advance width. + /// Other fields are initialized to default values. + /// + public ShapedGlyph(ushort glyphId, int xAdvance) + { + GlyphId = glyphId; + XAdvance = (short)xAdvance; + BaseAdvance = (short)xAdvance; // Initially same + YAdvance = 0; + XOffset = 0; + YOffset = 0; + ClusterIndex = 0; + CharCount = 1; + Reserved = 0; + } + + /// + /// Creates a new shaped glyph with base and adjusted advance widths. + /// + public ShapedGlyph(ushort glyphId, short baseAdvance, short xAdvance, + ushort clusterIndex, byte charCount) + { + GlyphId = glyphId; + BaseAdvance = baseAdvance; + XAdvance = xAdvance; + YAdvance = 0; + XOffset = 0; + YOffset = 0; + ClusterIndex = clusterIndex; + CharCount = charCount; + Reserved = 0; + } + + /// + /// Creates a new shaped glyph with all fields specified. + /// + public ShapedGlyph(ushort glyphId, short baseAdvance, short xAdvance, short yAdvance, + short xOffset, short yOffset, ushort clusterIndex, byte charCount) + { + GlyphId = glyphId; + BaseAdvance = baseAdvance; + XAdvance = xAdvance; + YAdvance = yAdvance; + XOffset = xOffset; + YOffset = yOffset; + ClusterIndex = clusterIndex; + CharCount = charCount; + Reserved = 0; + } + + /// + /// Creates a new shaped glyph with default values. + /// + public ShapedGlyph() + { + CharCount = 1; // Default to single character + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapedLightText.cs b/src/EPPlus.Interfaces/Fonts/ShapedLightText.cs new file mode 100644 index 0000000000..ae8a187686 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapedLightText.cs @@ -0,0 +1,71 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 03/18/2026 EPPlus Software AB Lightweight multi-font aware shaping result + *************************************************************************************************/ +using System.Diagnostics; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Lightweight result of text shaping, optimized for measurement and wrapping. + /// Contains structs (8 bytes each) instead of full + /// objects, plus per-font metrics inherited from + /// for correct multi-font calculation. + /// + [DebuggerDisplay("Glyphs: {Glyphs.Length}, Fonts: {FontUnitsPerEm?.Length ?? 0}")] + public class ShapedLightText : ShapedTextBase + { + /// + /// Array of lightweight glyph widths with positioning information. + /// + public GlyphWidth[] Glyphs { get; set; } + + protected override int GetGlyphCount() => + Glyphs?.Length ?? 0; + + protected override int GetGlyphXAdvance(int index) => + Glyphs[index].XAdvance; + + protected override byte GetGlyphFontId(int index) => + Glyphs[index].FontId; + + /// + /// Fills a character width buffer with per-character widths in points. + /// Handles multi-font glyphs correctly. + /// + public void FillCharWidths(float fontSize, double[] charWidths, int textLength) + { + if (Glyphs == null) return; + + bool singleFont = FontUnitsPerEm != null && FontUnitsPerEm.Length == 1; + float singleScale = singleFont ? fontSize / FontUnitsPerEm[0] : 0f; + + foreach (var glyph in Glyphs) + { + int idx = glyph.ClusterIndex; + if (idx >= 0 && idx < textLength) + { + if (singleFont) + { + charWidths[idx] += glyph.XAdvance * singleScale; + } + else + { + float upm = (FontUnitsPerEm != null && glyph.FontId < FontUnitsPerEm.Length) + ? FontUnitsPerEm[glyph.FontId] + : 1000f; + charWidths[idx] += glyph.XAdvance * (fontSize / upm); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapedText.cs b/src/EPPlus.Interfaces/Fonts/ShapedText.cs new file mode 100644 index 0000000000..ad2bc0f96f --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapedText.cs @@ -0,0 +1,72 @@ + +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + 03/16/2026 EPPlus Software AB Multi-font aware width calculation + 03/18/2026 EPPlus Software AB Refactored to use ShapedTextBase + *************************************************************************************************/ +using System.Diagnostics; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Result of text shaping operation containing positioned glyphs. + /// Supports multi-font text (e.g., primary font + emoji fallback) where glyphs + /// may originate from fonts with different UnitsPerEm values. + /// + [DebuggerDisplay("Glyphs length: {Glyphs.Length}, OriginalText: {OriginalText}")] + public class ShapedText : ShapedTextBase + { + /// + /// Array of shaped glyphs with positioning information. + /// + public ShapedGlyph[] Glyphs { get; set; } + + /// + /// The original input text that was shaped. + /// + public string OriginalText { get; set; } + + /// + /// Total horizontal advance width in font design units. + /// Suitable for single-font comparisons (e.g. verifying kerning). + /// For multi-font text, use instead. + /// + public int TotalAdvanceWidth + { + get + { + int total = 0; + if (Glyphs != null) + { + foreach (var glyph in Glyphs) + total += glyph.XAdvance; + } + return total; + } + } + + protected override int GetGlyphCount() => + Glyphs?.Length ?? 0; + + protected override int GetGlyphXAdvance(int index) => + Glyphs[index].XAdvance; + + protected override byte GetGlyphFontId(int index) => + Glyphs[index].FontId; + + public ShapedText() + { + Glyphs = new ShapedGlyph[0]; + OriginalText = string.Empty; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapedTextBase.cs b/src/EPPlus.Interfaces/Fonts/ShapedTextBase.cs new file mode 100644 index 0000000000..295fb64db7 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapedTextBase.cs @@ -0,0 +1,129 @@ +/************************************************************************************************* + Required Notice: Copyright(C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 03/18/2026 EPPlus Software AB Base class for shaped text results + *************************************************************************************************/ + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Base class for shaped text results. Provides multi-font aware width and + /// line height calculation shared by both (full shaping) + /// and (lightweight measurement). + /// Subclasses provide glyph data via , + /// and . + /// + public abstract class ShapedTextBase + { + /// + /// UnitsPerEm indexed by FontId. Set by TextShaper after shaping. + /// + public ushort[] FontUnitsPerEm { get; set; } + + /// + /// Line height per FontId in design units. + /// Set by TextShaper after shaping. + /// + public int[] FontLineHeights { get; set; } + + /// + /// Number of glyphs in this result. + /// + protected abstract int GetGlyphCount(); + + /// + /// Gets the XAdvance of the glyph at the specified index. + /// + protected abstract int GetGlyphXAdvance(int index); + + /// + /// Gets the FontId of the glyph at the specified index. + /// + protected abstract byte GetGlyphFontId(int index); + + /// + /// Convert advance width to PDF points. + /// Handles multi-font text correctly by using each glyph's FontId to look up + /// the correct UnitsPerEm. + /// + public float GetWidthInPoints(float fontSize) + { + int count = GetGlyphCount(); + if (count == 0 || FontUnitsPerEm == null || FontUnitsPerEm.Length == 0) + return 0f; + + // Fast path: single font + if (FontUnitsPerEm.Length == 1) + { + int total = 0; + for (int i = 0; i < count; i++) + total += GetGlyphXAdvance(i); + return (total / (float)FontUnitsPerEm[0]) * fontSize; + } + + // Multi-font path + float totalWidth = 0f; + for (int i = 0; i < count; i++) + { + byte fontId = GetGlyphFontId(i); + float upm = fontId < FontUnitsPerEm.Length + ? FontUnitsPerEm[fontId] + : FontUnitsPerEm[0]; + totalWidth += (GetGlyphXAdvance(i) / upm) * fontSize; + } + return totalWidth; + } + + /// + /// Convert advance width to pixels. Multi-font aware. + /// + public float GetWidthInPixels(float fontSize, float dpi) + { + return GetWidthInPoints(fontSize) * (dpi / 72f); + } + + /// + /// Gets the line height (baseline-to-baseline distance) in points. + /// For multi-font text, returns the maximum line height across all fonts + /// used, ensuring the line is tall enough for every glyph. + /// + public float GetLineHeightInPoints(float fontSize) + { + if (FontLineHeights == null || FontLineHeights.Length == 0 || + FontUnitsPerEm == null || FontUnitsPerEm.Length == 0) + return fontSize; + + if (FontLineHeights.Length == 1) + return (FontLineHeights[0] / (float)FontUnitsPerEm[0]) * fontSize; + + // Multi-font — max across actually used fonts + int count = GetGlyphCount(); + float maxLineHeight = 0f; + uint seenFontIds = 0; // bit field, supports up to 32 fonts (more than enough) + + for (int i = 0; i < count; i++) + { + byte fontId = GetGlyphFontId(i); + uint bit = 1u << fontId; + if ((seenFontIds & bit) != 0) + continue; + seenFontIds |= bit; + + if (fontId < FontLineHeights.Length && fontId < FontUnitsPerEm.Length) + { + float lh = (FontLineHeights[fontId] / (float)FontUnitsPerEm[fontId]) * fontSize; + if (lh > maxLineHeight) + maxLineHeight = lh; + } + } + return maxLineHeight > 0f ? maxLineHeight : fontSize; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapedVerticalText.cs b/src/EPPlus.Interfaces/Fonts/ShapedVerticalText.cs new file mode 100644 index 0000000000..5df675f714 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapedVerticalText.cs @@ -0,0 +1,77 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical text shaping support + *************************************************************************************************/ +using System.Diagnostics; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Result of a vertical text shaping operation containing positioned glyphs. + /// Used for Excel vertical text mode (text rotation value 255). + /// Analogous to for horizontal text. + /// + [DebuggerDisplay("Glyphs length: {Glyphs.Length}, OriginalText: {OriginalText}")] + public class ShapedVerticalText + { + /// + /// The original input text that was shaped. + /// + public string OriginalText { get; set; } + + /// + /// Array of vertically shaped glyphs with positioning information. + /// Glyphs are ordered top-to-bottom. + /// + public VerticalShapedGlyph[] Glyphs { get; set; } + + /// + /// Total vertical advance height in font design units. + /// This is the sum of all glyph YAdvance values and represents + /// the total height of the text column. + /// + public int TotalAdvanceHeight + { + get + { + int total = 0; + if (Glyphs != null) + { + foreach (var glyph in Glyphs) + { + total += glyph.YAdvance; + } + } + return total; + } + } + + /// + /// Converts total advance height to points. + /// + /// Font size in points + /// Units per EM from the font head table + /// Height in points + public float GetHeightInPoints(float fontSize, float unitsPerEm) + { + return (TotalAdvanceHeight / unitsPerEm) * fontSize; + } + + /// + /// Creates a new ShapedVerticalText with default values. + /// + public ShapedVerticalText() + { + Glyphs = new VerticalShapedGlyph[0]; + OriginalText = string.Empty; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/ShapingOptions.cs b/src/EPPlus.Interfaces/Fonts/ShapingOptions.cs new file mode 100644 index 0000000000..a62ca99d72 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/ShapingOptions.cs @@ -0,0 +1,143 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/15/2025 EPPlus Software AB Initial implementation + *************************************************************************************************/ +using System.Collections.Generic; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Options for controlling text shaping behavior. + /// + public class ShapingOptions + { + /// + /// Whether to apply GSUB substitutions (ligatures, contextual alternates, etc.). + /// + public bool ApplySubstitutions { get; set; } + + /// + /// List of GSUB features to apply (e.g., "liga", "calt", "clig"). + /// If null or empty, all available features will be applied. + /// + public List GsubFeatures { get; set; } + + /// + /// Whether to apply GPOS positioning (kerning, mark positioning, etc.). + /// + public bool ApplyPositioning { get; set; } + + /// + /// List of GPOS features to apply (e.g., "kern", "mark"). + /// If null or empty, all available features will be applied. + /// + public List GposFeatures { get; set; } + + /// + /// Script tag for shaping (e.g., "latn" for Latin). + /// If null, will use default script. + /// + public string Script { get; set; } + + /// + /// Language tag for shaping (e.g., "SWE " for Swedish). + /// If null, will use default language. + /// + public string Language { get; set; } + + /// + /// Default shaping options: ligatures and kerning enabled. + /// + public static ShapingOptions Default + { + get + { + return new ShapingOptions + { + ApplySubstitutions = true, + GsubFeatures = new List { "liga", "clig" }, + ApplyPositioning = true, + GposFeatures = new List { "kern" }, + Script = "latn", + Language = null + }; + } + } + + /// + /// Fast shaping: no substitutions, only kerning. + /// Use for simple text measurement where ligatures are not important. + /// + public static ShapingOptions Fast + { + get + { + return new ShapingOptions + { + ApplySubstitutions = false, + GsubFeatures = null, + ApplyPositioning = true, + GposFeatures = new List { "kern" }, + Script = "latn", + Language = null + }; + } + } + + /// + /// Full shaping: all features enabled. + /// Use for high-quality rendering. + /// + public static ShapingOptions Full + { + get + { + return new ShapingOptions + { + ApplySubstitutions = true, + GsubFeatures = new List { "liga", "calt", "clig" }, + ApplyPositioning = true, + GposFeatures = new List { "kern", "mark" }, + Script = "latn", + Language = null + }; + } + } + + /// + /// No shaping: just map characters to glyphs. + /// Fastest option, but no ligatures or kerning. + /// + public static ShapingOptions None + { + get + { + return new ShapingOptions + { + ApplySubstitutions = false, + GsubFeatures = null, + ApplyPositioning = false, + GposFeatures = null, + Script = null, + Language = null + }; + } + } + + public ShapingOptions() + { + ApplySubstitutions = true; + ApplyPositioning = true; + GsubFeatures = new List(); + GposFeatures = new List(); + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/UnicodeScript.cs b/src/EPPlus.Interfaces/Fonts/UnicodeScript.cs new file mode 100644 index 0000000000..8da5e3c223 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/UnicodeScript.cs @@ -0,0 +1,74 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 05/20/2026 EPPlus Software AB Initial implementation + *************************************************************************************************/ +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Unicode scripts used for per-script glyph-level fallback. Each value corresponds + /// to a Unicode block or group of blocks that share a writing system, and is the key + /// for configuring fallback fonts via + /// EpplusFontConfiguration.SetScriptFallback(UnicodeScript, params string[]). + /// + /// Only scripts that are realistic in Office documents are included. Adding more is + /// straightforward but requires updating UnicodeScriptClassifier as well. + /// + public enum UnicodeScript + { + /// The character does not belong to any of the supported scripts. + Unknown = 0, + + /// Latin script (ASCII, Latin-1, Latin Extended). Covers English, most European languages. + Latin, + + /// Cyrillic script. Covers Russian, Ukrainian, Bulgarian, Serbian, and other Slavic languages. + Cyrillic, + + /// Greek script. Covers Modern and Polytonic Greek. + Greek, + + /// Arabic script. Covers Arabic, Persian, Urdu, and related languages. + Arabic, + + /// Hebrew script. + Hebrew, + + /// Thai script. + Thai, + + /// Devanagari script. Covers Hindi, Marathi, Nepali, and many other Indian languages. + Devanagari, + + /// CJK Unified Ideographs (Han characters). Used in Chinese, Japanese, Korean, Vietnamese. + Han, + + /// Japanese Hiragana syllabary. + Hiragana, + + /// Japanese Katakana syllabary. + Katakana, + + /// Korean Hangul script (syllables and Jamo). + Hangul, + + /// Emoji and pictographic symbols (U+1F300-U+1FAFF and related blocks). + Emoji, + + /// Mathematical symbols and operators (U+2200-U+22FF, U+27C0-U+27EF, U+2A00-U+2AFF). + Math, + + /// Currency symbols (U+20A0-U+20CF). + Currency, + + /// Box drawing, block elements, and miscellaneous symbols used in tables and diagrams. + Symbol + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/VerticalGlyphHeight.cs b/src/EPPlus.Interfaces/Fonts/VerticalGlyphHeight.cs new file mode 100644 index 0000000000..aae70c5df0 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/VerticalGlyphHeight.cs @@ -0,0 +1,49 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical text shaping support + *************************************************************************************************/ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Lightweight glyph representation optimized for vertical text measurement. + /// Contains only essential data needed for height calculations. + /// Analogous to for horizontal text. + /// This struct is 8 bytes total. + /// + [DebuggerDisplay("YAdvance: {YAdvance}, ClusterIndex: {ClusterIndex}, CharCount: {CharCount}")] + [StructLayout(LayoutKind.Sequential)] + public struct VerticalGlyphHeight + { + /// + /// Vertical advance height in font design units. + /// Sourced from the 'vmtx' table, or falls back to advanceWidth from 'hmtx'. + /// + public ushort YAdvance; + + /// + /// Index of the original character that produced this glyph. + /// Used to map glyph heights back to character positions. + /// Range: 0-65,535 characters per string. + /// + public ushort ClusterIndex; + + /// + /// Number of characters consumed by this glyph. + /// Typically 1 for vertical text (no ligatures in vertical pipeline). + /// + public byte CharCount; + + // 3 bytes padding to align to 8 bytes total + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/Fonts/VerticalShapedGlyph.cs b/src/EPPlus.Interfaces/Fonts/VerticalShapedGlyph.cs new file mode 100644 index 0000000000..5e83a5d573 --- /dev/null +++ b/src/EPPlus.Interfaces/Fonts/VerticalShapedGlyph.cs @@ -0,0 +1,98 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 02/19/2026 EPPlus Software AB Vertical text shaping support + *************************************************************************************************/ +using System.Diagnostics; + +namespace OfficeOpenXml.Interfaces.Fonts +{ + /// + /// Represents a shaped glyph with vertical positioning information. + /// Used for Excel vertical text mode (text rotation value 255). + /// All measurements are in font design units (not PDF points or pixels). + /// Analogous to for horizontal text. + /// + [DebuggerDisplay("GlyphId: {GlyphId}, YAdvance: {YAdvance}, CharCount: {CharCount}")] + public class VerticalShapedGlyph + { + /// + /// The glyph ID in the font. + /// Range: 0-65,535. + /// + public ushort GlyphId; + + /// + /// Vertical advance height in font design units. + /// Sourced from the 'vmtx' table (advanceHeight). + /// Falls back to advanceWidth from 'hmtx' if 'vmtx' is not present in the font. + /// + public ushort YAdvance; + + /// + /// Top side bearing in font design units. + /// Distance from the vertical origin to the top of the glyph bounding box. + /// Sourced from the 'vmtx' table (topSideBearing). + /// + public short TopSideBearing; + + /// + /// Horizontal advance width in font design units. + /// Sourced from the 'hmtx' table. + /// Used by the renderer to center the glyph horizontally in a vertical text column: + /// xOffset = (columnWidth - AdvanceWidth) / 2 + /// + public ushort AdvanceWidth; + + /// + /// Index of the original character that produced this glyph. + /// Used to map shaped glyphs back to character positions. + /// Range: 0-65,535 characters per string. + /// + public ushort ClusterIndex; + + /// + /// Number of characters consumed by this glyph. + /// Typically 1 for vertical text (no ligatures in vertical pipeline). + /// + public byte CharCount; + + /// + /// ID of the font that provided this glyph. + /// 0 = primary font, 1+ = fallback fonts. + /// + public byte FontId; + + // Total size: 10 bytes + 2 bytes padding = 12 bytes + + /// + /// Creates a new vertical shaped glyph with default values. + /// + public VerticalShapedGlyph() + { + CharCount = 1; + } + + /// + /// Creates a new vertical shaped glyph with all fields specified. + /// + public VerticalShapedGlyph(ushort glyphId, ushort yAdvance, short topSideBearing, ushort advanceWidth, + ushort clusterIndex, byte charCount, byte fontId = 0) + { + GlyphId = glyphId; + YAdvance = yAdvance; + TopSideBearing = topSideBearing; + AdvanceWidth = advanceWidth; + ClusterIndex = clusterIndex; + CharCount = charCount; + FontId = fontId; + } + } +} \ No newline at end of file diff --git a/src/EPPlus.Interfaces/RichText/IFontFormatBase.cs b/src/EPPlus.Interfaces/RichText/IFontFormatBase.cs new file mode 100644 index 0000000000..dfe46c4e93 --- /dev/null +++ b/src/EPPlus.Interfaces/RichText/IFontFormatBase.cs @@ -0,0 +1,27 @@ +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Interfaces.RichText +{ + public interface IFontFormatBase + { + public string Family { get; set; } + public FontSubFamily SubFamily { get; set; } + public float Size { get; set; } + + /// + /// Sets the underlying data properties to be equal to the font + /// + /// + public void SetFont(IFontFormatBase font); + + /// + /// Sets the underlying data properties to be equal to the font + /// + /// + public void SetFont(MeasurementFont font); + } +} diff --git a/src/EPPlus.Interfaces/RichText/IRichTextCollection.cs b/src/EPPlus.Interfaces/RichText/IRichTextCollection.cs new file mode 100644 index 0000000000..d603a5bd86 --- /dev/null +++ b/src/EPPlus.Interfaces/RichText/IRichTextCollection.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Interfaces.RichText +{ + public interface IRichTextCollection : IEnumerable + { + /// + /// The full text string of all richtext in the collection + /// + string Text { get; } + + /// + /// Collection containing the richtext objects + /// + /// + /// + IRichTextFormatEssential this[int index] { get; } + + /// + /// Number of items in the list + /// + int Count { get; } + + /// + /// Add a rich text string + /// + /// The text to add + /// Adds a new paragraph after the . This will add a new line break. + /// + public IRichTextFormatEssential Add(string Text, bool NewParagraph); + + /// + /// Insert a rich text string at the specified index. + /// + /// The zero-based index at which rich text should be inserted. + /// The text to insert. + /// + public IRichTextFormatEssential Insert(int index, string Text, bool NewParagraph); + + /// + /// Clear the collection + /// + public void Clear(); + + /// + /// Removes an item at the specific index + /// + /// + public void RemoveAt(int Index); + + public void Remove(IRichTextFormatEssential Item); + } +} diff --git a/src/EPPlus.Interfaces/RichText/IRichTextFormatEssential.cs b/src/EPPlus.Interfaces/RichText/IRichTextFormatEssential.cs new file mode 100644 index 0000000000..f0511dfb67 --- /dev/null +++ b/src/EPPlus.Interfaces/RichText/IRichTextFormatEssential.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Interfaces.RichText +{ + /// + /// The most basic rich text format + /// The only properties that belong in this class are those that are absolutely neccesary for Measuring the text correctly + /// + public interface IRichTextFormatEssential : IFontFormatBase + { + /// + /// The text within the rich text + /// The most essential part to measure + /// + string Text { get; set; } + + /// + /// This MUST interact with font data subfamily + /// + bool Italic { get; set; } + /// + /// This MUST interact with font data subfamily + /// + bool Bold { get; set; } + } +} diff --git a/src/EPPlus.Interfaces/RichText/ITextFragmentBase.cs b/src/EPPlus.Interfaces/RichText/ITextFragmentBase.cs new file mode 100644 index 0000000000..0985fc2fd5 --- /dev/null +++ b/src/EPPlus.Interfaces/RichText/ITextFragmentBase.cs @@ -0,0 +1,23 @@ +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Interfaces.RichText +{ + public interface ITextFragmentBase + { + public string Text { get; set; } + /// + /// Store rich-text info. + /// We must extract font info from this but nothing else is supposed to be done with this within opentype + /// but we hold the data so users may more easily recognize which rich text this is in the output. + /// + public IRichTextFormatEssential RichTextOptions { get; set; } + public ShapingOptions Options { get; set; } + public double AscentPoints { get; set; } + public double DescentPoints { get; set; } + + public abstract float Size { get;} + } +} diff --git a/src/EPPlus.Interfaces/RichText/ITextFragmentCollection.cs b/src/EPPlus.Interfaces/RichText/ITextFragmentCollection.cs new file mode 100644 index 0000000000..74ba063287 --- /dev/null +++ b/src/EPPlus.Interfaces/RichText/ITextFragmentCollection.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Interfaces.RichText +{ + internal interface ITextFragmentCollection : IEnumerable + { + /// + /// The full text string of all richtext in the collection + /// + string Text { get; } + + /// + /// Collection containing the richtext objects + /// + /// + /// + ITextFragmentBase this[int index] { get; } + + /// + /// Number of items in the list + /// + int Count { get; } + + /// + /// Add a rich text string + /// + /// The text to add + /// Adds a new paragraph after the . This will add a new line break. + /// + public ITextFragmentBase Add(string Text, bool NewParagraph); + + /// + /// Insert a rich text string at the specified index. + /// + /// The zero-based index at which rich text should be inserted. + /// The text to insert. + /// + public ITextFragmentBase Insert(int index, string Text, bool NewParagraph); + + /// + /// Clear the collection + /// + public void Clear(); + + /// + /// Removes an item at the specific index + /// + /// + public void RemoveAt(int Index); + + public void Remove(ITextFragmentBase Item); + } +} diff --git a/src/EPPlus.System.Drawing/EPPlus.System.Drawing.csproj b/src/EPPlus.System.Drawing/EPPlus.System.Drawing.csproj index a9361e06e8..8b3cbde274 100644 --- a/src/EPPlus.System.Drawing/EPPlus.System.Drawing.csproj +++ b/src/EPPlus.System.Drawing/EPPlus.System.Drawing.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0;net8.0;netstandard2.1;netstandard2.0;net462;net35 + net10.0;net9.0;net8.0;netstandard2.1;netstandard2.0;net462 8.4.0.0 8.4.0.0 8.4.0 diff --git a/src/EPPlus.sln b/src/EPPlus.sln index 707a706121..55d05b41f8 100644 --- a/src/EPPlus.sln +++ b/src/EPPlus.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.0.11217.181 d18.0 +VisualStudioVersion = 18.2.11415.280 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPPlus", "EPPlus\EPPlus.csproj", "{219F673E-6115-4858-9E07-E33D24E795FE}" EndProject @@ -17,6 +17,26 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPPlus.Interfaces", "EPPlus EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPPlus.System.Drawing", "EPPlus.System.Drawing\EPPlus.System.Drawing.csproj", "{A1AF6174-CC8C-4BFD-B0EC-928C22CC4361}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{493FDAEB-6437-4804-8AC4-752B8F6E0400}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Fonts.OpenType", "EPPlus.Fonts.OpenType\EPPlus.Fonts.OpenType.csproj", "{B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Export.Pdf", "EPPlus.Export.Pdf\EPPlus.Export.Pdf.csproj", "{0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.DrawingRenderer.Tests", "EPPlus.DrawingRenderer.Tests\EPPlus.DrawingRenderer.Tests.csproj", "{A41EC1A4-8008-4943-AA29-A6D83918751F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Export.Pdf.Tests", "EPPlus.Export.Pdf.Tests\EPPlus.Export.Pdf.Tests.csproj", "{72041196-84B2-47B4-974D-B9FC0F8EF71A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Fonts.OpenType.Tests", "EPPlus.Fonts.OpenType.Tests\EPPlus.Fonts.OpenType.Tests.csproj", "{5B32877D-0439-43FE-B0DA-8EECE71656FF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Graphics", "EPPlus.Graphics\EPPlus.Graphics.csproj", "{DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Graphics.Tests", "EPPlus.Graphics.Tests\EPPlus.Graphics.Tests.csproj", "{AB5242C2-70DD-1D89-D731-92F4A334ABEE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.Fonts.OpenType.Benchmarks", "EPPlus.Fonts.OpenType.Benchmarks\EPPlus.Fonts.OpenType.Benchmarks.csproj", "{0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlus.DrawingRenderer", "EPPlus.DrawingRenderer\EPPlus.DrawingRenderer.csproj", "{6ED08425-EBB9-45AB-A023-34D4C72837D2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,10 +68,72 @@ Global {A1AF6174-CC8C-4BFD-B0EC-928C22CC4361}.Release 4.0|Any CPU.Build.0 = Release|Any CPU {A1AF6174-CC8C-4BFD-B0EC-928C22CC4361}.Release|Any CPU.ActiveCfg = Release|Any CPU {A1AF6174-CC8C-4BFD-B0EC-928C22CC4361}.Release|Any CPU.Build.0 = Release|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B30FA06C-B8B9-4D4C-8D41-FABC117FEBE4}.Release|Any CPU.Build.0 = Release|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D6A557E-FCD3-42A8-A5D1-C3CD5C0EF9E5}.Release|Any CPU.Build.0 = Release|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A41EC1A4-8008-4943-AA29-A6D83918751F}.Release|Any CPU.Build.0 = Release|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72041196-84B2-47B4-974D-B9FC0F8EF71A}.Release|Any CPU.Build.0 = Release|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B32877D-0439-43FE-B0DA-8EECE71656FF}.Release|Any CPU.Build.0 = Release|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE84719D-C6D4-4189-B4CD-D4D7429DF8E2}.Release|Any CPU.Build.0 = Release|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB5242C2-70DD-1D89-D731-92F4A334ABEE}.Release|Any CPU.Build.0 = Release|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA}.Release|Any CPU.Build.0 = Release|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Release 4.0|Any CPU.ActiveCfg = Release|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Release 4.0|Any CPU.Build.0 = Release|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6ED08425-EBB9-45AB-A023-34D4C72837D2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {78F198E4-B502-425D-BCC7-BF7F93B1EED9} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + {A41EC1A4-8008-4943-AA29-A6D83918751F} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + {72041196-84B2-47B4-974D-B9FC0F8EF71A} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + {5B32877D-0439-43FE-B0DA-8EECE71656FF} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + {AB5242C2-70DD-1D89-D731-92F4A334ABEE} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + {0A9F017E-F24A-4E3B-B9A9-477D7A4724AA} = {493FDAEB-6437-4804-8AC4-752B8F6E0400} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C73D0F5D-0C5D-4F85-8140-3598595AD2E1} EndGlobalSection diff --git a/src/EPPlus/BorderStyleBase.cs b/src/EPPlus/BorderStyleBase.cs new file mode 100644 index 0000000000..9b0d577c6a --- /dev/null +++ b/src/EPPlus/BorderStyleBase.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//namespace OfficeOpenXml +//{ +// public enum BorderStyleBase +// { +// /// +// /// No border style +// /// +// None, +// /// +// /// Hairline +// /// +// Hair, + +// /// +// /// Dashed +// /// +// Dashed, //dash + +// /// +// /// Dash Dot +// /// +// DashDot, //DashDot + +// /// +// /// Dotted +// /// +// Dotted, //Dot + +// /// +// /// Single line, medium thickness +// /// +// Medium, //solid + + + + +// /// +// /// Thin single line +// /// +// Thin, + +// /// +// /// Dash Dot Dot +// /// +// DashDotDot, +// /// +// /// Dash Dot Dot, medium thickness +// /// +// MediumDashDotDot, +// /// +// /// Dashed, medium thickness +// /// +// MediumDashed, +// /// +// /// Dash Dot, medium thickness +// /// +// MediumDashDot, +// /// +// /// Single line, Thick +// /// +// Thick, +// /// +// /// Double line +// /// +// Double, +// /// +// /// Slanted Dash Dot +// /// +// SlantDashDot +// } +//} diff --git a/src/EPPlus/CellPictures/ExcelCellPicture.cs b/src/EPPlus/CellPictures/ExcelCellPicture.cs index 523c83fe8e..5a2b652fd2 100644 --- a/src/EPPlus/CellPictures/ExcelCellPicture.cs +++ b/src/EPPlus/CellPictures/ExcelCellPicture.cs @@ -64,7 +64,7 @@ public Uri ExternalAddress } /// - /// Type of cell picture + /// BulletType of cell picture /// public ExcelCellPictureTypes PictureType { diff --git a/src/EPPlus/CellPictures/ExcelCellPictureTypes.cs b/src/EPPlus/CellPictures/ExcelCellPictureTypes.cs index 7fcf2a82c3..5defec4b63 100644 --- a/src/EPPlus/CellPictures/ExcelCellPictureTypes.cs +++ b/src/EPPlus/CellPictures/ExcelCellPictureTypes.cs @@ -27,7 +27,7 @@ public enum ExcelCellPictureTypes /// LocalImage, /// - /// Image that is retrieved via an URL. + /// BulletImage that is retrieved via an URL. /// WebImage } diff --git a/src/EPPlus/Compatibility/CompatibilitySettings.cs b/src/EPPlus/Compatibility/CompatibilitySettings.cs index 211a0c6d49..e1bc0a3460 100644 --- a/src/EPPlus/Compatibility/CompatibilitySettings.cs +++ b/src/EPPlus/Compatibility/CompatibilitySettings.cs @@ -52,7 +52,7 @@ internal CompatibilitySettings(ExcelPackage excelPackage) /// /// /// - /// + /// /// /// /// diff --git a/src/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs b/src/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs index 95d3f288af..b09b321d37 100644 --- a/src/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs +++ b/src/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs @@ -52,7 +52,7 @@ public interface IExcelConditionalFormattingRule /// bool PivotTable { get; set; } /// - /// Type case propterty for the base class. + /// BulletType case propterty for the base class. /// ExcelConditionalFormattingAsType As { get; } } diff --git a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs index f226ff88c0..be0a1c4ca5 100644 --- a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs +++ b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs @@ -145,7 +145,7 @@ internal void ReadExtConditionalFormattings(XmlReader xr) if (xr.GetAttribute("type") == "dataBar") { - //cfRule->Type + //cfRule->BulletType xr.Read(); var dataBar = (ExcelConditionalFormattingDataBar)localAndExtDict[id]; @@ -264,7 +264,7 @@ internal void ReadExtConditionalFormattings(XmlReader xr) { int priority = int.Parse(xr.GetAttribute("priority")); - //cfRule->Type + //cfRule->BulletType xr.Read(); string iconSet = xr.GetAttribute("iconSet"); @@ -1782,7 +1782,7 @@ public IExcelConditionalFormattingTwoColorScale AddTwoColorScale( /// Add ThreeIconSet Rule /// /// The address - /// Type of iconset + /// BulletType of iconset /// public IExcelConditionalFormattingThreeIconSet AddThreeIconSet(ExcelAddress Address, eExcelconditionalFormatting3IconsSetType IconSet) { @@ -1798,7 +1798,7 @@ public IExcelConditionalFormattingThreeIconSet /// The address - /// Type of iconset + /// BulletType of iconset /// public IExcelConditionalFormattingThreeIconSet AddThreeIconSet(string Address, eExcelconditionalFormatting3IconsSetType IconSet) { diff --git a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs index d88a03f717..abe825acd3 100644 --- a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs +++ b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs @@ -15,7 +15,7 @@ Date Author Change namespace OfficeOpenXml.ConditionalFormatting { /// - /// Enum for Conditional Format Type ST_CfType §18.18.12. With some changes. + /// Enum for Conditional Format BulletType ST_CfType §18.18.12. With some changes. /// public enum eExcelConditionalFormattingRuleType { @@ -23,39 +23,39 @@ public enum eExcelConditionalFormattingRuleType /// /// Highlights cells that are above the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType AboveAverage = 0, /// /// Highlights cells that are above or equal to the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType AboveOrEqualAverage = 1, /// /// Highlights cells that are below the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowAverage = 2, /// /// Highlights cells that are below or equal to the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowOrEqualAverage = 3, #endregion #region StdDev /// /// Highlights cells that are above the standard deviation for all values in the range. - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType /// AboveStdDev = 4, /// /// Highlights cells that are below the standard deviation for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowStdDev = 5, #endregion @@ -63,25 +63,25 @@ public enum eExcelConditionalFormattingRuleType /// /// Highlights cells whose values fall in the bottom N bracket as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType Bottom = 6, /// /// Highlights cells whose values fall in the bottom N percent as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType BottomPercent = 7, /// /// Highlights cells whose values fall in the top N bracket as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType Top = 8, /// /// Highlights cells whose values fall in the top N percent as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType TopPercent = 9, #endregion @@ -89,61 +89,61 @@ public enum eExcelConditionalFormattingRuleType /// /// Highlights cells containing dates in the last 7 days. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType Last7Days = 10, /// /// Highlights cells containing dates in the last month. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType LastMonth = 11, /// /// Highlights cells containing dates in the last week. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType LastWeek = 12, /// /// Highlights cells containing dates in the next month. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType NextMonth = 13, /// /// Highlights cells containing dates in the next week. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType NextWeek = 14, /// /// Highlights cells containing dates in this month. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType ThisMonth = 15, /// /// Highlights cells containing dates in this week. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType ThisWeek = 16, /// /// Highlights cells containing todays date. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType Today = 17, /// /// Highlights cells containing tomorrows date. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType Tomorrow = 18, /// /// Highlights cells containing yesterdays date. /// - /// TimePeriod Excel CF Rule Type + /// TimePeriod Excel CF Rule BulletType Yesterday = 19, #endregion @@ -154,13 +154,13 @@ public enum eExcelConditionalFormattingRuleType /// /// Equivalent to using the LEFT() sheet function and comparing values. /// - /// BeginsWith Excel CF Rule Type + /// BeginsWith Excel CF Rule BulletType BeginsWith = 20, /// /// Highlights cells in the range between the given two formulas. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType Between = 21, /// @@ -171,7 +171,7 @@ public enum eExcelConditionalFormattingRuleType /// characters that TRIM() would remove, then it is considered blank. An empty cell /// is also considered blank. /// - /// ContainsBlanks Excel CF Rule Type + /// ContainsBlanks Excel CF Rule BulletType ContainsBlanks = 22, /// @@ -181,7 +181,7 @@ public enum eExcelConditionalFormattingRuleType /// Equivalent to using ISERROR() sheet function to determine if there is /// a formula error. /// - /// ContainsErrors Excel CF Rule Type + /// ContainsErrors Excel CF Rule BulletType ContainsErrors = 23, /// @@ -191,13 +191,13 @@ public enum eExcelConditionalFormattingRuleType /// /// Equivalent to using the LEFT() sheet function and comparing values. /// - /// ContainsText Excel CF Rule Type + /// ContainsText Excel CF Rule BulletType ContainsText = 24, /// /// Highlights duplicated values. /// - /// DuplicateValues Excel CF Rule Type + /// DuplicateValues Excel CF Rule BulletType DuplicateValues = 25, /// @@ -206,55 +206,55 @@ public enum eExcelConditionalFormattingRuleType /// /// Equivalent to using the RIGHT() sheet function and comparing values. /// - /// EndsWith Excel CF Rule Type + /// EndsWith Excel CF Rule BulletType EndsWith = 26, /// /// Highlights cells equal to the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType Equal = 27, /// /// This rule contains a formula to evaluate. When the formula result is true, the cell is highlighted. /// - /// Expression Excel CF Rule Type + /// Expression Excel CF Rule BulletType Expression = 28, /// /// Highlights cells greater than the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType GreaterThan = 29, /// /// Highlights cells greater than or equal the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType GreaterThanOrEqual = 30, /// /// Highlights cells less than the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType LessThan = 31, /// /// Highlights cells less than or equal the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType LessThanOrEqual = 32, /// /// Highlights cells outside the range in given two formulas. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType NotBetween = 33, /// /// Highlights cells that does not contains the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType NotContains = 34, /// @@ -265,7 +265,7 @@ public enum eExcelConditionalFormattingRuleType /// characters that TRIM() would remove, then it is considered blank. An empty cell /// is also considered blank. /// - /// NotContainsBlanks Excel CF Rule Type + /// NotContainsBlanks Excel CF Rule BulletType NotContainsBlanks = 35, /// @@ -275,7 +275,7 @@ public enum eExcelConditionalFormattingRuleType /// Equivalent to using ISERROR() sheet function to determine if there is a /// formula error. /// - /// NotContainsErrors Excel CF Rule Type + /// NotContainsErrors Excel CF Rule BulletType NotContainsErrors = 36, /// @@ -284,19 +284,19 @@ public enum eExcelConditionalFormattingRuleType /// /// Equivalent to using the SEARCH() sheet function. /// - /// NotContainsText Excel CF Rule Type + /// NotContainsText Excel CF Rule BulletType NotContainsText = 37, /// /// . /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType NotEqual = 38, /// /// Highlights unique values in the range. /// - /// UniqueValues Excel CF Rule Type + /// UniqueValues Excel CF Rule BulletType UniqueValues = 39, #endregion @@ -304,13 +304,13 @@ public enum eExcelConditionalFormattingRuleType /// /// Three Color Scale (Low, Middle and High Color Scale) /// - /// ColorScale Excel CF Rule Type + /// ColorScale Excel CF Rule BulletType ThreeColorScale = 40, /// /// Two Color Scale (Low and High Color Scale) /// - /// ColorScale Excel CF Rule Type + /// ColorScale Excel CF Rule BulletType TwoColorScale = 41, #endregion @@ -319,21 +319,21 @@ public enum eExcelConditionalFormattingRuleType /// This conditional formatting rule applies a 3 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType ThreeIconSet = 42, /// /// This conditional formatting rule applies a 4 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType FourIconSet = 43, /// /// This conditional formatting rule applies a 5 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType FiveIconSet = 44, #endregion @@ -341,13 +341,13 @@ public enum eExcelConditionalFormattingRuleType /// /// This conditional formatting rule displays a gradated data bar in the range of cells. /// - /// DataBar Excel CF Rule Type + /// DataBar Excel CF Rule BulletType DataBar = 45 #endregion } /// - /// Enum for Conditional Format Value Object Type ST_CfvoType §18.18.13 + /// Enum for Conditional Format Value Object BulletType ST_CfvoType §18.18.13 /// public enum eExcelConditionalFormattingValueObjectType { @@ -413,7 +413,7 @@ public enum eExcelConditionalFormattingValueObjectPosition } /// - /// Enum for Conditional Formatting Value Object Node Type + /// Enum for Conditional Formatting Value Object Node BulletType /// public enum eExcelConditionalFormattingValueObjectNodeType { @@ -429,7 +429,7 @@ public enum eExcelConditionalFormattingValueObjectNodeType } /// - /// Enum for Conditional Formatting Operartor Type ST_ConditionalFormattingOperator §18.18.15 + /// Enum for Conditional Formatting Operartor BulletType ST_ConditionalFormattingOperator §18.18.15 /// public enum eExcelConditionalFormattingOperatorType { @@ -495,7 +495,7 @@ public enum eExcelConditionalFormattingOperatorType } /// - /// Enum for Conditional Formatting Time Period Type ST_TimePeriod §18.18.82 + /// Enum for Conditional Formatting Time Period BulletType ST_TimePeriod §18.18.82 /// public enum eExcelConditionalFormattingTimePeriodType { @@ -551,7 +551,7 @@ public enum eExcelConditionalFormattingTimePeriodType } /// - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 3 icons + /// 18.18.42 ST_IconSetType (Icon Set BulletType) - Only 3 icons /// public enum eExcelconditionalFormatting3IconsSetType { @@ -609,7 +609,7 @@ public enum eExcelconditionalFormatting3IconsSetType } /// - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 4 icons + /// 18.18.42 ST_IconSetType (Icon Set BulletType) - Only 4 icons /// public enum eExcelconditionalFormatting4IconsSetType { @@ -640,7 +640,7 @@ public enum eExcelconditionalFormatting4IconsSetType } /// - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 5 icons + /// 18.18.42 ST_IconSetType (Icon Set BulletType) - Only 5 icons /// public enum eExcelconditionalFormatting5IconsSetType { @@ -672,7 +672,7 @@ public enum eExcelconditionalFormatting5IconsSetType Boxes } /// - /// 18.18.42 ST_IconSetType (Icon Set Type) + /// 18.18.42 ST_IconSetType (Icon Set BulletType) /// public enum eExcelconditionalFormattingIconsSetType { @@ -1108,39 +1108,39 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// /// Highlights cells that are above the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType AboveAverage = 0, /// /// Highlights cells that are above or equal to the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType AboveOrEqualAverage = 1, /// /// Highlights cells that are below the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowAverage = 2, /// /// Highlights cells that are below or equal to the average for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowOrEqualAverage = 3, #endregion #region StdDev /// /// Highlights cells that are above the standard deviation for all values in the range. - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType /// AboveStdDev = 4, /// /// Highlights cells that are below the standard deviation for all values in the range. /// - /// AboveAverage Excel CF Rule Type + /// AboveAverage Excel CF Rule BulletType BelowStdDev = 5, #endregion @@ -1148,25 +1148,25 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// /// Highlights cells whose values fall in the bottom N bracket as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType Bottom = 6, /// /// Highlights cells whose values fall in the bottom N percent as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType BottomPercent = 7, /// /// Highlights cells whose values fall in the top N bracket as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType Top = 8, /// /// Highlights cells whose values fall in the top N percent as specified. /// - /// Top10 Excel CF Rule Type + /// Top10 Excel CF Rule BulletType TopPercent = 9, #endregion @@ -1175,7 +1175,7 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// /// Highlights cells in the range between the given two formulas. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType Between = 21, /// @@ -1186,7 +1186,7 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// characters that TRIM() would remove, then it is considered blank. An empty cell /// is also considered blank. /// - /// ContainsBlanks Excel CF Rule Type + /// ContainsBlanks Excel CF Rule BulletType ContainsBlanks = 22, /// @@ -1196,49 +1196,49 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// Equivalent to using ISERROR() sheet function to determine if there is /// a formula error. /// - /// ContainsErrors Excel CF Rule Type + /// ContainsErrors Excel CF Rule BulletType ContainsErrors = 23, /// /// Highlights cells equal to the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType Equal = 27, /// /// This rule contains a formula to evaluate. When the formula result is true, the cell is highlighted. /// - /// Expression Excel CF Rule Type + /// Expression Excel CF Rule BulletType Expression = 28, /// /// Highlights cells greater than the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType GreaterThan = 29, /// /// Highlights cells greater than or equal the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType GreaterThanOrEqual = 30, /// /// Highlights cells less than the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType LessThan = 31, /// /// Highlights cells less than or equal the given formula. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType LessThanOrEqual = 32, /// /// Highlights cells outside the range in given two formulas. /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType NotBetween = 33, /// @@ -1249,7 +1249,7 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// characters that TRIM() would remove, then it is considered blank. An empty cell /// is also considered blank. /// - /// NotContainsBlanks Excel CF Rule Type + /// NotContainsBlanks Excel CF Rule BulletType NotContainsBlanks = 35, /// @@ -1259,13 +1259,13 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// Equivalent to using ISERROR() sheet function to determine if there is a /// formula error. /// - /// NotContainsErrors Excel CF Rule Type + /// NotContainsErrors Excel CF Rule BulletType NotContainsErrors = 36, /// /// . /// - /// CellIs Excel CF Rule Type + /// CellIs Excel CF Rule BulletType NotEqual = 38, #endregion @@ -1273,13 +1273,13 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// /// Three Color Scale (Low, Middle and High Color Scale) /// - /// ColorScale Excel CF Rule Type + /// ColorScale Excel CF Rule BulletType ThreeColorScale = 40, /// /// Two Color Scale (Low and High Color Scale) /// - /// ColorScale Excel CF Rule Type + /// ColorScale Excel CF Rule BulletType TwoColorScale = 41, #endregion @@ -1288,21 +1288,21 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// This conditional formatting rule applies a 3 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType ThreeIconSet = 42, /// /// This conditional formatting rule applies a 4 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType FourIconSet = 43, /// /// This conditional formatting rule applies a 5 set icons to cells according /// to their values. /// - /// IconSet Excel CF Rule Type + /// IconSet Excel CF Rule BulletType FiveIconSet = 44, #endregion @@ -1310,7 +1310,7 @@ public enum eExcelPivotTableConditionalFormattingRuleType /// /// This conditional formatting rule displays a gradated data bar in the range of cells. /// - /// DataBar Excel CF Rule Type + /// DataBar Excel CF Rule BulletType DataBar = 45 #endregion } diff --git a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconSetBase.cs b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconSetBase.cs index 7f2652cd34..76baec402c 100644 --- a/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconSetBase.cs +++ b/src/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconSetBase.cs @@ -332,7 +332,7 @@ internal List GetCustomIconList(bool protected int CalculateCorrectIcon(ExcelAddress address, ExcelConditionalFormattingIconDataBarValue[] icons) { - //Icon1.Type + //Icon1.BulletType var range = _ws.Cells[address.Address]; var cellValue = range.Value; if(cellValue.IsNumeric() && cellValue != null) diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs index 856840547b..42bc6c2ff9 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs @@ -74,9 +74,9 @@ internal ExcelConditionalFormattingBetween( internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false && string.IsNullOrEmpty(Formula2) == false) + if (string.IsNullOrEmpty(Formula) == false && string.IsNullOrEmpty(Formula2) == false) { - var str = cellValue.ToString(); + var str = cellValue == null ? string.Empty : cellValue.ToString(); calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address), address.FullAddress, false).ToString(), CultureInfo.InvariantCulture); calculatedFormula2 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address, true), address.FullAddress, false).ToString(), CultureInfo.InvariantCulture); @@ -85,6 +85,11 @@ internal override bool ShouldApplyToCell(ExcelAddress address) var Formula2IsNum = double.TryParse(calculatedFormula2, NumberStyles.Float, CultureInfo.InvariantCulture, out double num2); var cellValueIsNum = double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out double numCellValue); + if (cellValue == null || str.Length == 0) + { + cellValueIsNum = true; + numCellValue = 0d; + } if (Formula1IsNum && Formula2IsNum) { if (cellValueIsNum) diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs index 3d563652d6..4c6b153074 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs @@ -59,21 +59,26 @@ internal ExcelConditionalFormattingGreaterThan(ExcelConditionalFormattingGreater internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false) + if (string.IsNullOrEmpty(Formula) == false) { calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address)).ToString(), CultureInfo.InvariantCulture); if(double.TryParse(calculatedFormula1, out double result)) { - if(cellValue.IsNumeric()) + if (cellValue == null || (cellValue is string s && s.Length == 0)) + { + return 0d > result; + } + if (cellValue.IsNumeric()) { return Convert.ToDouble(cellValue) > result; } } - else - { - var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); - return compareResult > 0; - } + + } + else if(cellValue != null) + { + var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); + return compareResult > 0; } return false; diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs index 75a1c6a910..34bfe31bbc 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs @@ -63,21 +63,25 @@ internal override ExcelConditionalFormattingRule Clone(ExcelWorksheet newWs = nu internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false) + if (string.IsNullOrEmpty(Formula) == false) { calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address)).ToString(), CultureInfo.InvariantCulture); if (double.TryParse(calculatedFormula1, out double result)) { + if (cellValue == null || (cellValue is string s && s.Length == 0)) + { + return 0d >= result; + } if (cellValue.IsNumeric()) { return Convert.ToDouble(cellValue) >= result; } } - else - { - var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); - return compareResult >= 0; - } + } + else if(cellValue != null) + { + var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); + return compareResult >= 0; } return false; diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs index 92ecf173e1..2bb23cd750 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs @@ -49,24 +49,27 @@ internal override ExcelConditionalFormattingRule Clone(ExcelWorksheet newWs = nu internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false) + if (string.IsNullOrEmpty(Formula) == false) { calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address)).ToString(), CultureInfo.InvariantCulture); if (double.TryParse(calculatedFormula1, out double result)) { + if (cellValue == null || (cellValue is string s && s.Length == 0)) + { + return 0d < result; + } if (cellValue.IsNumeric()) { return Convert.ToDouble(cellValue) < result; } } - else - { - var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); - return compareResult < 0; - } } - - return false; + else if (cellValue != null) + { + var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); + return compareResult < 0; + } + return false; } } } diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs index 993d659685..ee0b8669fb 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs @@ -63,21 +63,25 @@ internal override ExcelConditionalFormattingRule Clone(ExcelWorksheet newWs = nu internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false) + if (string.IsNullOrEmpty(Formula) == false) { calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address)).ToString(), CultureInfo.InvariantCulture); if (double.TryParse(calculatedFormula1, out double result)) { + if (cellValue == null || (cellValue is string s && s.Length == 0)) + { + return 0d <= result; + } if (cellValue.IsNumeric()) { return Convert.ToDouble(cellValue) <= result; } } - else - { - var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); - return compareResult <= 0; - } + } + else if (cellValue != null) + { + var compareResult = string.Compare(calculatedFormula1, cellValue.ToString(), true); + return compareResult <= 0; } return false; diff --git a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs index 1e777a9181..94d8bf8ec6 100644 --- a/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs +++ b/src/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs @@ -79,9 +79,9 @@ internal override ExcelConditionalFormattingRule Clone(ExcelWorksheet newWs = nu internal override bool ShouldApplyToCell(ExcelAddress address) { var cellValue = _ws.Cells[address.Address].Value; - if (cellValue != null && string.IsNullOrEmpty(Formula) == false && string.IsNullOrEmpty(Formula2) == false) + if (string.IsNullOrEmpty(Formula) == false && string.IsNullOrEmpty(Formula2) == false) { - var str = cellValue.ToString(); + var str = cellValue == null ? string.Empty : cellValue.ToString(); calculatedFormula1 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address), address.FullAddress, false).ToString(), CultureInfo.InvariantCulture); calculatedFormula2 = string.Format(_ws.Workbook.FormulaParserManager.Parse(GetCellFormula(address, true), address.FullAddress, false).ToString(), CultureInfo.InvariantCulture); @@ -90,6 +90,11 @@ internal override bool ShouldApplyToCell(ExcelAddress address) var Formula2IsNum = double.TryParse(calculatedFormula2, NumberStyles.Float, CultureInfo.InvariantCulture, out double num2); var cellValueIsNum = double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out double numCellValue); + if (cellValue == null || str.Length == 0) + { + cellValueIsNum = true; + numCellValue = 0d; + } if (Formula1IsNum && Formula2IsNum) { if (cellValueIsNum) diff --git a/src/EPPlus/Core/AutofitHelper.cs b/src/EPPlus/Core/AutofitHelper.cs index 968f1abae7..098bfa6508 100644 --- a/src/EPPlus/Core/AutofitHelper.cs +++ b/src/EPPlus/Core/AutofitHelper.cs @@ -18,6 +18,10 @@ Date Author Change using System.Collections.Generic; using System.Linq; using static OfficeOpenXml.ExcelAddressBase; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Fonts.OpenType; namespace OfficeOpenXml.Core { @@ -46,6 +50,10 @@ public AutofitHelper(ExcelRangeBase range) internal void AutofitColumn(double MinimumWidth, double MaximumWidth) { var worksheet = _range._worksheet; + if(worksheet is not ExcelWorksheet ew2) + { + + } if (worksheet.Dimension == null) { return; diff --git a/src/EPPlus/Core/CellStore/CellStore.cs b/src/EPPlus/Core/CellStore/CellStore.cs index 1d86c8986b..20c486f412 100644 --- a/src/EPPlus/Core/CellStore/CellStore.cs +++ b/src/EPPlus/Core/CellStore/CellStore.cs @@ -19,7 +19,7 @@ namespace OfficeOpenXml.Core.CellStore /// internal static class CellStoreSettings { - /**** Size constants ****/ + /**** FontSize constants ****/ internal const int _pageBits = 13; // 13bits = 8192 Note: Maximum is 13 bits since short is used (PageMax=16K) internal const int _pageSize = 1 << _pageBits; internal const int _pageSizeMax = _pageSize << 1; diff --git a/src/EPPlus/Core/Worksheet/Fonts/BoundingRectangle.cs b/src/EPPlus/Core/Worksheet/Fonts/BoundingRectangle.cs index 50cfcf6134..776e063f9f 100644 --- a/src/EPPlus/Core/Worksheet/Fonts/BoundingRectangle.cs +++ b/src/EPPlus/Core/Worksheet/Fonts/BoundingRectangle.cs @@ -10,10 +10,6 @@ Date Author Change ************************************************************************************************* 12/26/2021 EPPlus Software AB EPPlus 6.0 *************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace OfficeOpenXml.Core.Worksheet.Fonts { diff --git a/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurer.cs b/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurer.cs index 990dc86d1f..4c037d0c0b 100644 --- a/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurer.cs +++ b/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurer.cs @@ -24,7 +24,7 @@ internal class GenericFontMetricsTextMeasurer : GenericFontMetricsTextMeasurerBa /// Only CR, LF or CRLF should be considered. /// public bool MeasureWrappedTextCells -{ + { get; set; } diff --git a/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurerBase.cs b/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurerBase.cs index 5ceab9145e..a79de9c1eb 100644 --- a/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurerBase.cs +++ b/src/EPPlus/Core/Worksheet/Fonts/GenericFontMetrics/GenericFontMetricsTextMeasurerBase.cs @@ -49,6 +49,10 @@ internal protected bool IsValidFont(uint fontKey) internal protected TextMeasurement MeasureTextInternal(string text, uint fontKey, MeasurementFontStyles style, float size, bool wrapText = false) { + if(text==null) + { + return new TextMeasurement(0, 0); + } var sFont = _fonts[fontKey]; var width = 0f; var maxWidth = 0f; @@ -61,7 +65,8 @@ internal protected TextMeasurement MeasureTextInternal(string text, uint fontKey { if(x>0 && c=='\r' && text[x-1]=='\n') { - continue; //CRLF should be handled as one new line. + continue; //CRLF should be handle + //d as one new line. } if(width>maxWidth) { diff --git a/src/EPPlus/DataValidation/ExcelDataValidation.cs b/src/EPPlus/DataValidation/ExcelDataValidation.cs index 5deb7db824..f5d02965ef 100644 --- a/src/EPPlus/DataValidation/ExcelDataValidation.cs +++ b/src/EPPlus/DataValidation/ExcelDataValidation.cs @@ -285,7 +285,7 @@ bool IsEntireColumn(string address) } /// - /// Type to determine if extLst or not + /// BulletType to determine if extLst or not /// internal InternalValidationType InternalValidationType { get; set; } = InternalValidationType.DataValidation; diff --git a/src/EPPlus/DigitalSignatures/ExcelDigitalSignature.cs b/src/EPPlus/DigitalSignatures/ExcelDigitalSignature.cs index d7272fcb83..ea4a48399a 100644 --- a/src/EPPlus/DigitalSignatures/ExcelDigitalSignature.cs +++ b/src/EPPlus/DigitalSignatures/ExcelDigitalSignature.cs @@ -62,7 +62,7 @@ public X509Certificate2 Certificate /// public string PurposeForSigning { get; set; } = ""; /// - /// Commitment Type. + /// Commitment BulletType. /// public CommitmentType CommitmentTyping = CommitmentType.None; @@ -438,6 +438,7 @@ internal void CreateSignatureLineReferences(ref ExcelSignedXml signedXml) { if(SignatureLine != null) { + //Worrying Reference validImageReference = new() { Type = "http://www.w3.org/2000/09/xmldsig#Object", diff --git a/src/EPPlus/DigitalSignatures/XAdES/SignedSignatureProperties.cs b/src/EPPlus/DigitalSignatures/XAdES/SignedSignatureProperties.cs index 1a873f4cec..d6723d9426 100644 --- a/src/EPPlus/DigitalSignatures/XAdES/SignedSignatureProperties.cs +++ b/src/EPPlus/DigitalSignatures/XAdES/SignedSignatureProperties.cs @@ -133,7 +133,6 @@ internal SignedSignatureProperties(string prefix, X509Certificate2 cert, Additio _info = info; var bytes = Cert.GetSerialNumber(); - //Array.Reverse(bytes); bytes = bytes.AsEnumerable().Reverse().ToArray(); Serial = BytesToNumericString(bytes); } diff --git a/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartEx.cs b/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartEx.cs index 2fc564abeb..3efd6fb60a 100644 --- a/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartEx.cs +++ b/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartEx.cs @@ -344,7 +344,7 @@ public override ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(this, NameSpaceManager, ChartXml.SelectSingleNode("cx:chartSpace", NameSpaceManager), "cx:txPr/a:p/a:pPr/a:defRPr", _chartXmlHelper.SchemaNodeOrder); + _font = new ExcelTextFontXml(this, NameSpaceManager, ChartXml.SelectSingleNode("cx:chartSpace", NameSpaceManager), "cx:txPr/a:p/a:pPr/a:defRPr", _chartXmlHelper.SchemaNodeOrder); } return _font; } @@ -359,7 +359,7 @@ public override ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, ChartXml.SelectSingleNode("cx:chartSpace", NameSpaceManager), "cx:txPr/a:bodyPr", _chartXmlHelper.SchemaNodeOrder); + _textBody = new ExcelTextBody(this, NameSpaceManager, ChartXml.SelectSingleNode("cx:chartSpace", NameSpaceManager), "cx:txPr/a:bodyPr", _chartXmlHelper.SchemaNodeOrder); } return _textBody; } diff --git a/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartExAxis.cs b/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartExAxis.cs index b0bf6e0751..d7be5cdad5 100644 --- a/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartExAxis.cs +++ b/src/EPPlus/Drawing/Chart/ChartEx/ExcelChartExAxis.cs @@ -12,6 +12,7 @@ Date Author Change *************************************************************************************************/ using OfficeOpenXml.Utils.EnumUtils; using System; +using System.Collections.Generic; using System.Xml; namespace OfficeOpenXml.Drawing.Chart.ChartEx @@ -189,6 +190,11 @@ internal override ExcelChartTitle GetTitle() return _title; } + internal override List GetAxisValues(out bool isCount) + { + throw new NotImplementedException(); + } + /// /// This property is not used for extended charts. Trying to set this property will result in a NotSupportedException. /// @@ -276,6 +282,16 @@ internal override eAxisType AxisType } } } + /// + /// True if the axis has a title. + /// + public override bool HasTitle + { + get + { + return TopNode.SelectSingleNode($"{_nsPrefix}:title", NameSpaceManager)==null; + } + } } } diff --git a/src/EPPlus/Drawing/Chart/ExcelBarChart.cs b/src/EPPlus/Drawing/Chart/ExcelBarChart.cs index 654fc52751..75f8d035ab 100644 --- a/src/EPPlus/Drawing/Chart/ExcelBarChart.cs +++ b/src/EPPlus/Drawing/Chart/ExcelBarChart.cs @@ -240,7 +240,7 @@ public int Overlap { get { - return _chartXmlHelper.GetXmlNodeInt(_overlapPath); + return _chartXmlHelper.GetXmlNodeInt(_overlapPath, 0); } set { diff --git a/src/EPPlus/Drawing/Chart/ExcelChart.cs b/src/EPPlus/Drawing/Chart/ExcelChart.cs index 1a4c37d7c1..a0a94f4968 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChart.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChart.cs @@ -24,6 +24,7 @@ Date Author Change using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Text; using System.Xml; @@ -105,7 +106,7 @@ private bool HasPrimaryAxis() return false; } internal abstract void AddAxis(); - bool _secondaryAxis = false; + bool? _secondaryAxis = null; /// /// If true the charttype will use the secondary axis. /// The chart must contain a least one other charttype that uses the primary axis. @@ -114,7 +115,11 @@ public bool UseSecondaryAxis { get { - return _secondaryAxis; + if (_secondaryAxis.HasValue == false) + { + _secondaryAxis = Array.FindIndex(Axis, x => ((ExcelChartAxis)x).Id == YAxis.Id) > 1; + } + return _secondaryAxis.Value; } set { @@ -178,7 +183,7 @@ public override eDrawingType DrawingType } /// - /// Type of chart + /// BulletType of chart /// public eChartType ChartType { get; internal set; } /// @@ -588,7 +593,7 @@ protected internal bool IsTypeStacked() /// Returns true if the chart is of type clustered /// /// True if the chart is of type clustered - protected bool IsTypeClustered() + protected internal bool IsTypeClustered() { return ChartType == eChartType.BarClustered || ChartType == eChartType.BarClustered3D || @@ -602,6 +607,50 @@ protected bool IsTypeClustered() ChartType == eChartType.PyramidColClustered; } /// + /// Returns true if the chart is of type bar chart + /// + /// True if the chart is of type bar + protected internal bool IsTypeBar() + { + return ChartType == eChartType.BarClustered || + ChartType == eChartType.BarStacked || + ChartType == eChartType.BarStacked100 || + ChartType == eChartType.BarClustered3D || + ChartType == eChartType.BarStacked3D || + ChartType == eChartType.BarStacked1003D || + ChartType == eChartType.ConeBarClustered || + ChartType == eChartType.ConeBarStacked || + ChartType == eChartType.ConeBarStacked100 || + ChartType == eChartType.CylinderBarClustered || + ChartType == eChartType.CylinderBarStacked || + ChartType == eChartType.CylinderBarStacked100 || + ChartType == eChartType.PyramidBarClustered || + ChartType == eChartType.PyramidBarStacked || + ChartType == eChartType.PyramidBarStacked100; + } + /// + /// Returns true if the chart is of type column chart + /// + /// True if the chart is of type column + protected internal bool IsTypeColumn() + { + return ChartType == eChartType.ColumnClustered || + ChartType == eChartType.ColumnStacked || + ChartType == eChartType.ColumnStacked100 || + ChartType == eChartType.ColumnClustered3D || + ChartType == eChartType.ColumnStacked3D || + ChartType == eChartType.ColumnStacked1003D || + ChartType == eChartType.ConeColClustered || + ChartType == eChartType.ConeColStacked || + ChartType == eChartType.ConeColStacked100 || + ChartType == eChartType.CylinderColClustered || + ChartType == eChartType.CylinderColStacked || + ChartType == eChartType.CylinderColStacked100 || + ChartType == eChartType.PyramidColClustered || + ChartType == eChartType.PyramidColStacked || + ChartType == eChartType.PyramidColStacked100; + } + /// /// Returns true if the chart is a pie or Doughnut chart /// /// True if the chart is a pie or Doughnut chart @@ -1171,6 +1220,7 @@ internal virtual bool IsAxisTypeSupported(eAxisType type, ExcelChartAxis axis) internal override void SaveDrawing(bool hasLoadedPivotTables) { + TextBody.SaveTextBody(); base.SaveDrawing(hasLoadedPivotTables); var chartStream = Part.GetStream(FileMode.Create, FileAccess.Write); diff --git a/src/EPPlus/Drawing/Chart/ExcelChartAxis.cs b/src/EPPlus/Drawing/Chart/ExcelChartAxis.cs index 1161309132..264249edd5 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartAxis.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartAxis.cs @@ -18,6 +18,7 @@ Date Author Change using OfficeOpenXml.Utils.EnumUtils; using System; using System.Reflection.Emit; +using System.Collections.Generic; namespace OfficeOpenXml.Drawing.Chart { @@ -27,7 +28,7 @@ namespace OfficeOpenXml.Drawing.Chart public abstract class ExcelChartAxis : XmlHelper, IDrawingStyle, IStyleMandatoryProperties { /// - /// Type of axis + /// BulletType of axis /// internal ExcelChart _chart; internal string _nsPrefix; @@ -223,7 +224,7 @@ public ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + _font = new ExcelTextFontXml(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _font; } @@ -238,7 +239,9 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, Font.CreateTopNode); + //TODO: CreateTopNode of ExcelTextFontXML on init here somehow + //Note: txPR is a CT_Textbody node. The only difference between txPr and TextBody + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, ((ExcelTextFontXml)Font).CreateTopNode); } return _textBody; } @@ -461,7 +464,23 @@ public bool HasMinorGridlines { return ExistsNode(_minorGridlinesPath); } - } + } + + /// + /// True if the axis has a title. + /// + public abstract bool HasTitle + { + get; + } + internal bool IsVertical + { + get + { + return AxisPosition == eAxisPosition.Left || AxisPosition == eAxisPosition.Right; + } + } + ///  /// Removes Major and Minor gridlines from the Axis ///  @@ -581,5 +600,6 @@ void IStyleMandatoryProperties.SetMandatoryProperties() CreatespPrNode($"{_nsPrefix}:spPr"); } + internal abstract List GetAxisValues(out bool isCount); } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartAxisStandard.cs b/src/EPPlus/Drawing/Chart/ExcelChartAxisStandard.cs index 0115b2077f..7d4174febf 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartAxisStandard.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartAxisStandard.cs @@ -10,10 +10,23 @@ Date Author Change ************************************************************************************************* 04/22/2020 EPPlus Software AB Added this class *************************************************************************************************/ +using OfficeOpenXml.ExternalReferences; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Finance; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Information; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Utils.EnumUtils; +using OfficeOpenXml.Utils.TypeConversion; using System; -using System.Xml; +using System.Collections; +using System.Collections.Generic; using System.Globalization; -using OfficeOpenXml.Utils.EnumUtils; +using System.Linq; +using System.Reflection.Emit; +using System.Xml; +using static OfficeOpenXml.Style.XmlAccess.ExcelNumberFormatXml; namespace OfficeOpenXml.Drawing.Chart { /// @@ -42,13 +55,15 @@ public sealed class ExcelChartAxisStandard : ExcelChartAxis }; internal static string[] _schemaNodeOrderCat = new string[] { "auto", "lblAlgn", "lblOffset", "tickLblSkip", "tickMarkSkip", "noMultiLvlLbl", "extLst" }; internal static string[] _schemaNodeOrderDate = new string[] { "auto", "lblOffset", "baseTimeUnit", "majorUnit", "majorTimeUnit", "minorUnit", "minorTimeUnit", "extLst" }; - internal static string[] _schemaNodeOrderSer = new string[] { "tickLblSkip", "tickMarkSkip","extLst" }; - internal static string[] _schemaNodeOrderVal = new string[] { "crossBetween", "majorUnit", "minorUnit", "dispUnits", "extLst" }; + internal static string[] _schemaNodeOrderSer = new string[] { "tickLblSkip", "tickMarkSkip", "extLst" }; + internal static string[] _schemaNodeOrderVal = new string[] { "crossBetween", "majorUnit", "minorUnit", "dispUnits", "extLst" }; - internal ExcelChartAxisStandard(ExcelChart chart, XmlNamespaceManager nameSpaceManager, XmlNode topNode, string nsPrefix) : base(chart, nameSpaceManager, topNode, nsPrefix) + internal ExcelChartAxisStandard(ExcelChart chart, XmlNamespaceManager nameSpaceManager, XmlNode topNode, string nsPrefix, int index) : base(chart, nameSpaceManager, topNode, nsPrefix) { AddSchemaNodeOrder(new string[] { "axId", "scaling", "delete", "axPos", "majorGridlines", "minorGridlines", "title", "numFmt", "majorTickMark", "minorTickMark", "tickLblPos", "spPr", "txPr", "crossAx", "crosses", "crossesAt", "crossBetween", "auto", "lblOffset", "baseTimeUnit", "majorUnit", "majorTimeUnit", "minorUnit", "minorTimeUnit", "tickLblSkip", "tickMarkSkip", "dispUnits", "noMultiLvlLbl", "logBase", "orientation", "max", "min" }, ExcelDrawing._schemaNodeOrderSpPr); + + Index = index; } internal override string Id { @@ -62,7 +77,7 @@ internal override string Id /// /// Get or Sets the major tick marks for the axis. /// - public override eAxisTickMark MajorTickMark + public override eAxisTickMark MajorTickMark { get { @@ -75,7 +90,7 @@ public override eAxisTickMark MajorTickMark { try { - return (eAxisTickMark)Enum.Parse(typeof(eAxisTickMark), v, true /* ignoreCase */); + return (eAxisTickMark)Enum.Parse(typeof(eAxisTickMark), v, true); } catch { @@ -105,7 +120,7 @@ public override eAxisTickMark MinorTickMark { try { - return (eAxisTickMark)Enum.Parse(typeof(eAxisTickMark), v, true /* ignoreCase */); + return (eAxisTickMark)Enum.Parse(typeof(eAxisTickMark), v, true); } catch { @@ -144,6 +159,86 @@ internal set } } /// + /// Returns the actual position of the axis, taking into account the position and the label position. + /// For example, if the axis position is left and the label position is high, the actual position will be to the right of the plotarea. + /// + public eActualAxisPosition ActualAxisPosition + { + get + { + var ap = AxisPosition; + if (ap == eAxisPosition.Left && LabelPosition == eTickLabelPosition.High) + { + return eActualAxisPosition.Right; + } + else if (ap == eAxisPosition.Bottom) + { + if (LabelPosition == eTickLabelPosition.High) + { + return eActualAxisPosition.Top; + } + else + { + return eActualAxisPosition.Bottom; + } + } + else if (ap == eAxisPosition.Right) + { + if (LabelPosition == eTickLabelPosition.Low) + { + if (_chart.Axis.FirstOrDefault(x => x.AxisPosition == eAxisPosition.Left)?.LabelPosition != eTickLabelPosition.Low) + { + return eActualAxisPosition.Left; + } + else + { + return eActualAxisPosition.LeftSecond; + } + } + else + { + if (_chart.Axis.FirstOrDefault(x => x.AxisPosition == eAxisPosition.Left)?.LabelPosition != eTickLabelPosition.High) + { + return eActualAxisPosition.Right; + } + else + { + return eActualAxisPosition.RightSecond; + } + } + } + else if(ap==eAxisPosition.Top) + { + if (LabelPosition == eTickLabelPosition.Low) + { + if (_chart.Axis.FirstOrDefault(x => x.AxisPosition == eAxisPosition.Bottom)?.LabelPosition != eTickLabelPosition.Low) + { + return eActualAxisPosition.Bottom; + } + else + { + return eActualAxisPosition.BottomSecond; + } + } + else + { + if (_chart.Axis.FirstOrDefault(x => x.AxisPosition == eAxisPosition.Bottom)?.LabelPosition != eTickLabelPosition.High) + { + return eActualAxisPosition.Top; + } + else + { + return eActualAxisPosition.TopSecond; + } + } + } + else + { + return (eActualAxisPosition)ap; + } + } + } + /// /// Chart axis title /// public new ExcelChartTitleStandard Title @@ -153,7 +248,16 @@ internal set return (ExcelChartTitleStandard)GetTitle(); } } - + /// + /// True if the axis has a title. + /// + public override bool HasTitle + { + get + { + return TopNode.SelectSingleNode("c:title", NameSpaceManager) != null; + } + } internal override ExcelChartTitle GetTitle() { if (_title == null) @@ -328,6 +432,25 @@ public override double? CrossesAt } } } + ExcelChartAxisStandard _crossingAxis=null; + /// + /// The crossing axis for this axis. For a value axis, this is the category axis and for a category axis this is the value axis. + /// + internal ExcelChartAxisStandard CrossingAxis + { + get + { + if (_crossingAxis == null) + { + var cAxId = GetXmlNodeString("c:crossAx/@val"); + if(string.IsNullOrEmpty(cAxId)==false) + { + _crossingAxis = _chart.Axis.Where(x => x.Id == cAxId).FirstOrDefault() as ExcelChartAxisStandard; + } + } + return _crossingAxis; + } + } /// /// If the axis is deleted /// @@ -367,6 +490,57 @@ public override eTickLabelPosition TickLabelPosition SetXmlNodeString(_ticLblPos_Path, v); } } + const string _label_alignment_path = "c:lblAlgn/@val"; + /// + /// Set the alingment for the axis labels within the major tickmarks. + /// + public eAxisLabelAlignment LabelAlignment + { + get + { + switch(GetXmlNodeString(_label_alignment_path)) + { + case "l": + return eAxisLabelAlignment.Left; + case "r": + return eAxisLabelAlignment.Right; + default: + return eAxisLabelAlignment.Center; + } + } + set + { + string v; + switch (value) + { + case eAxisLabelAlignment.Left: + v = "l"; + break; + case eAxisLabelAlignment.Right: + v = "r"; + break; + default: + v = "ctr"; + break; + } + SetXmlNodeString(_label_alignment_path, v); + } + } + const string _label_offset_path = "c:lblOffset/@val"; + /// + /// Set the offset in whole percent between the labels and the axis. + /// + public int LabelOffset + { + get + { + return GetXmlNodeInt(_label_offset_path, 100); + } + set + { + SetXmlNodeInt(_label_offset_path, value, null, false); + } + } const string _displayUnitPath = "c:dispUnits/c:builtInUnit/@val"; const string _custUnitPath = "c:dispUnits/c:custUnit/@val"; /// @@ -577,7 +751,7 @@ public override double? LogBase { if (value == null) { - DeleteNode(_logbasePath,true); + DeleteNode(_logbasePath, true); } else { @@ -641,5 +815,336 @@ public void AddTitle(ExcelRangeBase linkedCell) Title.LinkedCell = linkedCell; _chart.ApplyStyleOnPart(Title, _chart._styleManager?.Style?.AxisTitle); } + /// + /// The axis data is specified on the range data, not specified, for a date or category axis + /// + public bool Auto + { + get + { + return GetXmlNodeBool("c:auto/@val"); + } + set + { + SetXmlNodeBool("c:auto/@val", value); + } + } + ExcelLayout _layout = null; + /// + /// Contains layout properties, if the title is manually positioned. + /// + public ExcelLayout Layout + { + get + { + if (_layout == null) + { + _layout = new ExcelLayout(NameSpaceManager, TopNode, "c:layout", "", SchemaNodeOrder); + } + return _layout; + } + } + /// + /// The index for the axis. + /// + public int Index { get; private set; } + internal bool IsDate + { + get + { + if (AxisType == eAxisType.Date) + { + return true; + } + else if (AxisType != eAxisType.Cat) + { + var nf = new ExcelFormatTranslator(Format, 0); + if (nf.DataType == eFormatType.DateTime) + { + return true; + } + } + return false; + } + } + + internal bool IsYAxis + { + get + { + foreach(var ct in _chart.PlotArea.ChartTypes) + { + if (ct.YAxis == this) + { + return true; + } + } + return false; + } + } + internal bool IsXAxis + { + get + { + foreach (var ct in _chart.PlotArea.ChartTypes) + { + if (ct.XAxis == this) + { + return true; + } + } + return false; + } + } + internal override List GetAxisValues(out bool isCount) + { + List> values; + GetSeriesValues(out isCount, out values); + var dl = values.SelectMany(x => x).Distinct().ToList(); + if (AxisType!=eAxisType.Cat) + { + dl.Sort(); + } + if (Orientation == eAxisOrientation.MaxMin) + { + dl.Reverse(); + } + return dl; + } + + internal void GetSeriesValues(out bool isCount, out List> values) + { + values = new List>(); + isCount = false; + List pl = new List(); + int ix = 0; + foreach (var ct in _chart.PlotArea.ChartTypes) + { + foreach (var serie in ct.Series) + { + var l = new List(); + values.Add(l); + if (AxisType == eAxisType.Cat) + { + if (string.IsNullOrEmpty(serie.XSeries) && (serie.NumberLiteralsX == null || serie.NumberLiteralsX.Length == 0) && (serie.StringLiteralsX == null || serie.StringLiteralsX?.Length == 0)) + { + AddCountFromSeries(l, serie.Series, serie.NumberLiteralsY, serie.StringLiteralsY); + isCount = true; + } + else + { + AddFromSerie(l, serie.XSeries, serie.NumberLiteralsX, serie.StringLiteralsX, true, new string[] { serie.HeaderAddress?.Address, serie.GetHeaderText(ix) }); + } + } + else + { + if (ct.YAxis.Id == Id) + { + AddFromSerie(l, serie.Series, serie.NumberLiteralsY, serie.StringLiteralsY, false, null, pl); + } + else if (ct.XAxis.Id == Id) + { + AddFromSerie(l, serie.XSeries, serie.NumberLiteralsX, serie.StringLiteralsX, false, null); + } + } + pl = l; + ix++; + } + } + if (_chart.IsTypePercentStacked() && IsYAxis) + { + CalculateStacked100(values); + } + } + + internal static void CalculateStacked100(List> values) + { + for (int i = 0; i < values[0].Count; i++) + { + double rowAbsSum = 0; + for (int k = 0; k < values.Count; k++) + { + var v = values[k][i]; + if (ConvertUtil.IsExcelNumeric(v)) + { + rowAbsSum += Math.Abs(ConvertUtil.GetValueDouble(v, true, true)); + } + } + var pv = 0D; + for (int j=0;j< values.Count;j++) + { + var val = values[j][i]; + if (ConvertUtil.IsExcelNumeric(val)) + { + double d = pv + ConvertUtil.GetValueDouble(val, true, true); + if (rowAbsSum != 0) + { + values[j][i] = d / rowAbsSum; + } + else + { + values[j][i] = 0; + } + pv = d; + } + } + } + } + private void AddCountFromSeries(List l, string address, double[] numberLiterals, string[] stringLiterals) + { + l.Add(1); + if (numberLiterals?.Length > 0) + { + l.Add(numberLiterals.Length); + } + else if (stringLiterals?.Length > 0) + { + l.Add(stringLiterals.Length); + } + else + { + var a = new ExcelAddressBase(address); + l.Add(Math.Max(a.Rows, a.Columns)); + } + } + + private void AddFromSerie(List list, string address, double[] numberLiterals, string[] stringLiterals, bool useText, string[] headerInfo, List prevList=null) + { + var isStacked = _chart.IsTypeStacked() && prevList != null; + if (numberLiterals?.Length > 0) + { + for (int i = 0; i < numberLiterals.Length; i++) + { + var n = numberLiterals[i]; + if (isStacked) + { + n += GetSerieValue(prevList, i); + } + list.Add(n); + } + } + else if (stringLiterals?.Length > 0) + { + foreach (var s in stringLiterals) + { + list.Add(s); + } + } + else + { + var a = new ExcelAddressBase(address); + if (a.ExternalReferenceIndex > 0) + { + GetExternalValues(list, useText, headerInfo, prevList, isStacked, a); + } + else + { + GetInternalValues(list, useText, headerInfo, prevList, isStacked, a); + } + } + } + + private void GetInternalValues(List list, bool useText, string[] headerInfo, List prevList, bool isStacked, ExcelAddressBase a) + { + var ws = _chart.WorkSheet.Workbook.Worksheets[a.WorkSheetName]; + if (ws != null) + { + GetValuesFromWorksheet(list, useText, headerInfo, prevList, isStacked, a, ws); + } + } + + private void GetValuesFromWorksheet(List list, bool useText, string[] headerInfo, List prevList, bool isStacked, ExcelAddressBase a, ExcelWorksheet ws) + { + var range = ws.Cells[a.Address]; + var i = 0; + for (var r = 0; r < range.Rows; r++) + { + for (var c = 0; c < range.Columns; c++) + { + var v = range.Offset(r, c, 1, 1); + if (useText) + { + if (headerInfo == null) + { + list.Add(v.Text); + } + else + { + list.Add(new string[] { v.Text, a.Address, headerInfo[1] }); + } + } + else + { + double d = ConvertUtil.GetValueDouble(v.Value, false, true); + if (double.IsNaN((double)d)) d = 0; + if (isStacked) + { + var pv = GetSerieValue(prevList, i++); + d += pv; + } + list.Add(d); + } + } + } + } + + private void GetExternalValues(List list, bool useText, string[] headerInfo, List prevList, bool isStacked, ExcelAddressBase a) + { + var wb = _chart.WorkSheet.Workbook; + if (wb.ExternalLinks.Count > a.ExternalReferenceIndex) return; + + var extRef = wb.ExternalLinks[a.ExternalReferenceIndex-1]; + if (extRef.ExternalLinkType != ExternalReferences.eExternalLinkType.ExternalWorkbook) return; + var extWb = extRef as ExcelExternalWorkbook; + if (extWb.Package == null) + { + var ws = extWb.CachedWorksheets[a.WorkSheetName]; + if (ws != null) + { + var i = 0; + for (var r = a._fromRow; r <= a._toRow; r++) + { + for (var c = a._fromCol; c <= a._toCol; c++) + { + var v = ws.CellValues[r, c]; + if (useText) + { + // if (headerInfo == null) + // { + // list.Add(v.Text); + // } + // else + // { + // list.Add(new string[] { v.Text, a.Address, headerInfo[1] }); + // } + list.Add(v.Value); + } + else + { + double d = ConvertUtil.GetValueDouble(v.Value, false, true); + if (double.IsNaN((double)d)) d = 0; + if (isStacked) + { + var pv = GetSerieValue(prevList, i++); + d += pv; + } + list.Add(d); + //} + } + } + } + } + } + } + private double GetSerieValue(List prevList, int i) + { + if (prevList.Count > i && ConvertUtil.IsExcelNumeric(prevList[i])) + { + var v=ConvertUtil.GetValueDouble(prevList[i], true, true); + if (double.IsNaN(v)) return 0d; + return v; + } + return 0d; + } } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs index 2e1036065c..363145d563 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs @@ -85,7 +85,7 @@ public abstract bool ShowLeaderLines set; } /// - /// Show Bubble Size + /// Show Bubble FontSize /// public abstract bool ShowBubbleSize { @@ -218,7 +218,7 @@ public ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, CreateDefaultText); + _font = new ExcelTextFontXml(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, CreateDefaultText); } return _font; } @@ -268,7 +268,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, Font.CreateTopNode); + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, ((ExcelTextFontXml)Font).CreateTopNode); } return _textBody; } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs index b2f4b9da29..3d8673c053 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs @@ -212,7 +212,7 @@ public override bool ShowLeaderLines } const string showBubbleSizePath = "c:showBubbleSize/@val"; /// - /// Show Bubble Size + /// Show Bubble FontSize /// public override bool ShowBubbleSize { diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataPoint.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataPoint.cs index 0009d146da..05c75aae6b 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartDataPoint.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartDataPoint.cs @@ -175,6 +175,28 @@ public bool HasMarker() return ExistsNode("c:marker"); } + const string explosionPath = "c:explosion/@val"; + + /// + /// Explosion + /// (only relevant in some charts e.g. Pie Charts) + /// + public int Explosion + { + get + { + return GetXmlNodeInt(explosionPath); + } + set + { + if (value < 0 || value > 400) + { + throw (new ArgumentOutOfRangeException("Explosion range is 0-400")); + } + SetXmlNodeString(explosionPath, value.ToString()); + } + } + /// /// Dispose the object /// diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataTable.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataTable.cs index 84090ff137..9ebe70e0ef 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartDataTable.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartDataTable.cs @@ -149,7 +149,7 @@ public ExcelTextFont Font CreateNode("c:txPr/a:bodyPr"); CreateNode("c:txPr/a:lstStyle"); } - _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, "c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + _font = new ExcelTextFontXml(_chart, NameSpaceManager, TopNode, "c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _font; } @@ -164,7 +164,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, "c:txPr/a:bodyPr", SchemaNodeOrder); + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, "c:txPr/a:bodyPr", SchemaNodeOrder); } return _textBody; } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartLegend.cs b/src/EPPlus/Drawing/Chart/ExcelChartLegend.cs index e52fb8a278..40e1cf5a59 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartLegend.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartLegend.cs @@ -120,10 +120,13 @@ internal List LoadLegendEntries() { if (this is ExcelChartExLegend) return new List(); //Legend entries are not applicable for extended charts. var entries = new List(); - var nodes = GetNodes("c:legendEntry"); - foreach(XmlNode n in nodes) + if (TopNode != null) { - entries.Add(new ExcelChartLegendEntry(NameSpaceManager, n, (ExcelChartStandard)_chart)); + var nodes = GetNodes("c:legendEntry"); + foreach (XmlNode n in nodes) + { + entries.Add(new ExcelChartLegendEntry(NameSpaceManager, n, (ExcelChartStandard)_chart)); + } } return entries; } @@ -228,7 +231,7 @@ public ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(_chart,NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + _font = new ExcelTextFontXml(_chart,NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _font; } @@ -243,7 +246,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:bodyPr", SchemaNodeOrder); + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:bodyPr", SchemaNodeOrder); } return _textBody; } @@ -296,6 +299,21 @@ public ExcelDrawing3D ThreeD return _threeD; } } + ExcelLayout _layout = null; + /// + /// Contains layout properties, if the legend is manually positioned. + /// + public ExcelLayout Layout + { + get + { + if (_layout == null) + { + _layout = new ExcelLayout(NameSpaceManager, TopNode, "c:layout", "", SchemaNodeOrder); + } + return _layout; + } + } void IDrawingStyleBase.CreatespPr() { CreatespPrNode($"{_nsPrefix}:spPr"); diff --git a/src/EPPlus/Drawing/Chart/ExcelChartLegendEntry.cs b/src/EPPlus/Drawing/Chart/ExcelChartLegendEntry.cs index 7afc28621c..f8e82d8138 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartLegendEntry.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartLegendEntry.cs @@ -91,7 +91,7 @@ private void CreateTopNode() } } - ExcelTextFont _font = null; + ExcelTextFontXml _font = null; /// /// The Font properties /// @@ -102,7 +102,7 @@ public ExcelTextFont Font if (_font == null) { CreateTopNode(); - _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, InitChartXml); + _font = new ExcelTextFontXml(_chart, NameSpaceManager, TopNode, $"c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, InitChartXml); } return _font; } @@ -134,7 +134,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"c:txPr/a:bodyPr", SchemaNodeOrder); + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"c:txPr/a:bodyPr", SchemaNodeOrder); } return _textBody; } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartLine.cs b/src/EPPlus/Drawing/Chart/ExcelChartLine.cs index 6e4a8f27f9..ef674d4422 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartLine.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartLine.cs @@ -102,6 +102,17 @@ void IDrawingStyleBase.CreatespPr() { CreatespPrNode(); } + + internal bool HasValue() + { + if(_threeD != null | _effect != null | _fill != null | _border != null) + { + return true; + } + + return false; + } + /// /// Removes the item /// diff --git a/src/EPPlus/Drawing/Chart/ExcelChartNumericSource.cs b/src/EPPlus/Drawing/Chart/ExcelChartNumericSource.cs index 07bfe3a79c..ba0a57cac9 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartNumericSource.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartNumericSource.cs @@ -13,6 +13,8 @@ Date Author Change using System.Xml; using System.Globalization; using System; +using System.Collections.Generic; +using OfficeOpenXml.Utils.TypeConversion; namespace OfficeOpenXml.Drawing.Chart { @@ -40,7 +42,7 @@ internal ExcelChartNumericSource(XmlNamespaceManager nameSpaceManager, XmlNode t case "numRef": _formatCode = GetXmlNodeString(_path + "/c:numRef/c:numCache/c:formatCode"); break; - } + } } } /// @@ -164,6 +166,61 @@ public string FormatCode _formatCode=value; } } + internal List GetValuesList(ExcelWorkbook wb) + { + var list = new List(); + var vs = ValuesSource; + if (_sourceElement?.LocalName=="numLit") + { + if (ValuesSource?.Length > 2) + { + var source = ValuesSource.Substring(1, ValuesSource.Length - 2).Split(','); + foreach(var s in source) + { + if(double.TryParse(s.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out double d)) + { + list.Add(d); + } + else + { + list.Add(0); + } + } + } + } + else + { + var adr = GetXmlNodeString($"{_path}/c:numRef/c:f"); + if (!string.IsNullOrEmpty(adr)) + { + if (ExcelCellBase.IsValidAddress(adr)) + { + var address = new ExcelAddressBase(adr); + var ws = wb.Worksheets[address.WorkSheetName]; + if (ws != null) + { + var range = ws.Cells[address.Address]; + for (var r = 0; r < range.Start.Row; r++) + { + for (var c = 0; c < range.Start.Row; c++) + { + var v = range.Offset(r, c); + if (ConvertUtil.IsExcelNumeric(v.Value)) + { + list.Add(ConvertUtil.GetValueDouble(v.Value, false)); + } + else + { + list.Add(0D); + } + } + } + } + } + } + } + return list; + } } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartPlotArea.cs b/src/EPPlus/Drawing/Chart/ExcelChartPlotArea.cs index 6d2617727a..cd3afa3aaa 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartPlotArea.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartPlotArea.cs @@ -10,6 +10,7 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using OfficeOpenXml.ConditionalFormatting; using OfficeOpenXml.Drawing.Interfaces; using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Style.ThreeD; @@ -37,7 +38,7 @@ internal ExcelChartPlotArea(XmlNamespaceManager ns, XmlNode node, ExcelChart fir } else { - AddSchemaNodeOrder(new string[] { "areaChart", "area3DChart", "lineChart", "line3DChart", "stockChart", "radarChart", "scatterChart", "pieChart", "pie3DChart", "doughnutChart", "barChart", "bar3DChart", "ofPieChart", "surfaceChart", "surface3DChart", "valAx", "catAx", "dateAx", "serAx", "dTable", "spPr" }, + AddSchemaNodeOrder(new string[] { "layout","areaChart", "area3DChart", "lineChart", "line3DChart", "stockChart", "radarChart", "scatterChart", "pieChart", "pie3DChart", "doughnutChart", "barChart", "bar3DChart", "ofPieChart", "surfaceChart", "surface3DChart", "valAx", "catAx", "dateAx", "serAx", "dTable", "spPr" }, ExcelDrawing._schemaNodeOrderSpPr); } @@ -162,6 +163,21 @@ public ExcelDrawing3D ThreeD return _threeD; } } + ExcelLayout _layout = null; + /// + /// Contains layout properties, if the plotarea is manually positioned. + /// + public ExcelLayout Layout + { + get + { + if (_layout == null) + { + _layout = new ExcelLayout(NameSpaceManager, TopNode, "c:layout", "", SchemaNodeOrder); + } + return _layout; + } + } void IDrawingStyleBase.CreatespPr() { CreatespPrNode(); diff --git a/src/EPPlus/Drawing/Chart/ExcelChartSerie.cs b/src/EPPlus/Drawing/Chart/ExcelChartSerie.cs index 7bf436518f..580c003d56 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartSerie.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartSerie.cs @@ -10,17 +10,19 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.Linq; using OfficeOpenXml.Core.CellStore; -using System.Globalization; using OfficeOpenXml.Drawing.Interfaces; using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Style.ThreeD; +using OfficeOpenXml.ExternalReferences; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Xml; namespace OfficeOpenXml.Drawing.Chart { /// @@ -248,5 +250,78 @@ internal string ToFullAddress(string value) return value; } } + + internal string GetHeaderText(int index) + { + var ret = ""; + if(string.IsNullOrEmpty(Header) == false) + { + return Header; + } + else if (HeaderAddress != null) + { + return GetAddressValue(HeaderAddress); + } + return $"Series{index + 1}"; + } + + private string GetAddressValue(ExcelAddressBase address) + { + if (address.IsExternal) + { + var wb = _chart.WorkSheet.Workbook; + if (wb.ExternalLinks.Count < address.ExternalReferenceIndex) return ExcelErrorValue.Values.Ref; + var extWb = wb.ExternalLinks[address.ExternalReferenceIndex - 1] as ExcelExternalWorkbook; + if(extWb!=null) + { + if (extWb.Package == null) + { + var ws = extWb.CachedWorksheets[address.WorkSheetName]; + return ws.CellValues[address._fromRow, address._fromCol].Value.ToString(); + } + else + { + var ws = extWb.Package.Workbook.Worksheets[HeaderAddress.WorkSheetName]; + if (ws != null) + { + return ws.Cells[HeaderAddress.Address].Offset(0, 0).Text; + } + } + } + } + else + { + ExcelWorksheet ws; + if (string.IsNullOrEmpty(HeaderAddress.WorkSheetName)) + { + ws = _chart.WorkSheet; + } + else + { + ws = _chart.WorkSheet.Workbook.Worksheets[HeaderAddress.WorkSheetName]; + } + if (ws != null) + { + if (HeaderAddress.IsSingleCell) + { + return ws.Cells[HeaderAddress.Address].Offset(0, 0).Text; + } + else + { + var sb = new StringBuilder(); + foreach (var cell in ws.Cells[HeaderAddress.Address]) + { + if (sb.Length != 0) + { + sb.Append(" "); + } + sb.Append(cell.TextMerged); + } + return sb.ToString(); + } + } + } + return ExcelErrorValue.Values.Ref; + } } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs b/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs index b0ae3d77e2..e34f5a268a 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs @@ -27,7 +27,7 @@ public sealed class ExcelChartSerieDataLabel : ExcelChartDataLabelStandard internal ExcelChartSerieDataLabel(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, string[] schemaNodeOrder) : base(chart, ns, node, "dLbls", schemaNodeOrder) { - Position = eLabelPosition.Center; + //Position = eLabelPosition.Center; var parentSeries = GetParentSeries(); var strRef = parentSeries.GetDataLabelRange(); diff --git a/src/EPPlus/Drawing/Chart/ExcelChartStandard.cs b/src/EPPlus/Drawing/Chart/ExcelChartStandard.cs index 7847856a70..f7df55c8ec 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartStandard.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartStandard.cs @@ -129,7 +129,7 @@ private void Init(ExcelDrawings drawings, XmlNode chartNode) { _isChartEx = chartNode.NamespaceURI == ExcelPackage.schemaChartExMain; _chartXmlHelper = XmlHelperFactory.Create(drawings.NameSpaceManager, chartNode); - _chartXmlHelper.AddSchemaNodeOrder(new string[] { "date1904", "lang", "roundedCorners", "AlternateContent", "style", "clrMapOvr", "pivotSource", "protection", "chart", "ofPieType", "title", "autoTitleDeleted", "pivotFmts", "view3D", "floor", "sideWall", "backWall", "plotArea", "wireframe", "barDir", "grouping", "scatterStyle", "radarStyle", "varyColors", "ser", "dLbls", "bubbleScale", "showNegBubbles", "firstSliceAng", "holeSize", "dropLines", "hiLowLines", "upDownBars", "marker", "smooth", "shape", "legend", "plotVisOnly", "dispBlanksAs", "gapWidth", "upBars", "downBars", "showDLblsOverMax", "overlap", "bandFmts", "axId", "spPr", "txPr", "printSettings" }, ExcelDrawing._schemaNodeOrderSpPr); + _chartXmlHelper.AddSchemaNodeOrder(new string[] { "date1904", "lang", "roundedCorners", "AlternateContent", "style", "clrMapOvr", "pivotSource", "protection", "chart", "ofPieType", "title", "autoTitleDeleted", "pivotFmts", "view3D", "floor", "sideWall", "backWall", "plotArea", "wireframe", "barDir", "grouping", "scatterStyle", "radarStyle", "varyColors", "ser", "dLbls", "bubbleScale", "showNegBubbles", "firstSliceAng", "holeSize", "dropLines", "hiLowLines", "upDownBars", "marker", "smooth", "shape", "legend", "plotVisOnly", "dispBlanksAs", "gapWidth", "upBars", "downBars", "showDLblsOverMax", "overlap", "bandFmts", "axId", "tx", "layout", "overlay", "spPr", "txPr", "printSettings" }, ExcelDrawing._schemaNodeOrderSpPr); WorkSheet = drawings.Worksheet; } #endregion @@ -237,11 +237,12 @@ private void CreateNewChart(ExcelDrawings drawings, ExcelChart topChart, XmlDocu private void LoadAxis() { List l = new List(); + int i = 0; foreach (XmlNode node in _chartNode.ParentNode.ChildNodes) { if (node.NodeType == XmlNodeType.Element && node.LocalName.EndsWith("Ax")) { - ExcelChartAxis ax = new ExcelChartAxisStandard(this, NameSpaceManager, node, "c"); + ExcelChartAxis ax = new ExcelChartAxisStandard(this, NameSpaceManager, node, "c", i++); l.Add(ax); } } @@ -758,8 +759,8 @@ internal override void AddAxis() _axis = newAxis; } - _axis[_axis.Length - 2] = new ExcelChartAxisStandard(this, NameSpaceManager, catAx, "c"); - _axis[_axis.Length - 1] = new ExcelChartAxisStandard(this, NameSpaceManager, valAx, "c"); + _axis[_axis.Length - 2] = new ExcelChartAxisStandard(this, NameSpaceManager, catAx, "c", _axis.Length - 2); + _axis[_axis.Length - 1] = new ExcelChartAxisStandard(this, NameSpaceManager, valAx, "c", _axis.Length - 1); foreach (var chart in _plotArea.ChartTypes) { chart._axis = _axis; @@ -1076,7 +1077,7 @@ public override ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(this, NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager), "c:txPr/a:p/a:pPr/a:defRPr", _chartXmlHelper.SchemaNodeOrder); + _font = new ExcelTextFontXml(this, NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager), "c:txPr/a:p/a:pPr/a:defRPr", _chartXmlHelper.SchemaNodeOrder); } return _font; } @@ -1091,7 +1092,7 @@ public override ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager), "c:txPr/a:bodyPr", _chartXmlHelper.SchemaNodeOrder); + _textBody = new ExcelTextBody(this, NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager), "c:txPr/a:bodyPr", _chartXmlHelper.SchemaNodeOrder); } return _textBody; } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs b/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs index 744486ee74..82c91646fb 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs @@ -10,17 +10,19 @@ Date Author Change ************************************************************************************************* 05/15/2020 EPPlus Software AB EPPlus 5.2 *************************************************************************************************/ +using OfficeOpenXml.Core.CellStore; +using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using System; using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.Linq; -using OfficeOpenXml.Core.CellStore; using System.Globalization; -using System.Runtime.CompilerServices; using System.IO; using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Xml; namespace OfficeOpenXml.Drawing.Chart { @@ -319,6 +321,29 @@ public override ExcelAddressBase HeaderAddress SetXmlNodeString("c:tx/c:strRef/c:strCache/c:ptCount/@val", "0"); } } + + internal string GetHeaderString() + { + if(string.IsNullOrEmpty(Header)) + { + if(HeaderAddress == null) + { + return null; + } + + var ws = string.IsNullOrEmpty(HeaderAddress.WorkSheetName) ? _chart.WorkSheet : _chart.WorkSheet.Workbook.Worksheets[HeaderAddress.WorkSheetName]; + if (ws == null) //Worksheet does not exist, exit + { + return null; + } + return ws.Cells[HeaderAddress.Address].Text; + } + else + { + return Header; + } + } + string _seriesTopPath; string _seriesPath = "{0}/c:numRef/c:f"; string _numCachePath = "{0}/c:numRef/c:numCache"; @@ -657,10 +682,30 @@ public override int NumberOfItems { get { - if (ExcelCellBase.IsValidAddress(Series)) + string alteredSeries = Series; + //Some addresses are split and within parenthesis + if (Series.StartsWith("(")) + { + alteredSeries = alteredSeries.Trim('(', ')'); + } + + if (ExcelCellBase.IsValidAddress(alteredSeries)) { - var a = new ExcelAddressBase(Series); - return a.Rows; + var a = new ExcelAddressBase(alteredSeries); + if(a.Addresses == null) + { + return a.Rows; + } + else + { + //If the address is a split address + int numItems = 0; + foreach(var address in a.Addresses) + { + numItems += a.Rows; + } + return numItems; + } } else { diff --git a/src/EPPlus/Drawing/Chart/ExcelChartTitle.cs b/src/EPPlus/Drawing/Chart/ExcelChartTitle.cs index aa48f87f6b..abc58781fa 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartTitle.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartTitle.cs @@ -18,6 +18,7 @@ Date Author Change using OfficeOpenXml.Style; using System; using System.Collections.Generic; +using System.Net.Security; using System.Text; using System.Xml; @@ -31,16 +32,19 @@ public abstract class ExcelChartTitle : XmlHelper, IDrawingStyle, IStyleMandator internal ExcelChart _chart; internal string _nsPrefix = ""; internal string _fontPropertiesPath = ""; - + internal string _richTextPath = ""; + internal string _defTxBodyPath = ""; internal ExcelChartTitle(ExcelChart chart, XmlNamespaceManager nameSpaceManager, XmlNode node, string nsPrefix) : base(nameSpaceManager, node) { _chart = chart; _nsPrefix = nsPrefix; - _fontPropertiesPath = $"{_nsPrefix}:tx/{_nsPrefix}:rich"; + _fontPropertiesPath = $"{_nsPrefix}:txPr"; + _richTextPath = $"{_nsPrefix}:tx/{_nsPrefix}:rich"; + _defTxBodyPath = $"{_nsPrefix}:txPr"; if (chart._isChartEx) { - AddSchemaNodeOrder(new string[] { "tx", "strRef", "rich", "bodyPr", "lstStyle", "layout", "p", "overlay", "spPr", "txPr" }, ExcelDrawing._schemaNodeOrderSpPr); + AddSchemaNodeOrder(new string[] { "layout", "tx", "strRef", "rich", "bodyPr", "lstStyle", "layout", "p", "overlay", "spPr", "txPr" }, ExcelDrawing._schemaNodeOrderSpPr); CreateTopNode(); } else @@ -53,7 +57,6 @@ internal ExcelChartTitle(ExcelChart chart, XmlNamespaceManager nameSpaceManager, chart.ApplyStyleOnPart(this, chart.StyleManager?.Style?.Title, true); } } - } private void CreateTopNode() @@ -69,7 +72,7 @@ internal static string GetInitXml(string prefix) return $"<{prefix}:tx><{prefix}:rich>" + $"" + $"" + - $"" + + $"" + "" + $"<{prefix}:layout /><{prefix}:overlay val=\"0\" />" + $"<{prefix}:spPr>"; @@ -114,7 +117,7 @@ public ExcelDrawingFill Fill return _fill; } } - internal ExcelTextFont _font = null; + internal ExcelTextFontXml _font = null; /// /// A reference to the font properties /// @@ -124,11 +127,11 @@ public ExcelTextFont Font { if (_font == null) { - if (HasLinkedCell==false && (_richText == null || _richText.Count == 0)) - { - RichText.Add(""); - } - _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"{_fontPropertiesPath}/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + //if (HasLinkedCell==false && (_richText == null || _richText.Count == 0)) + //{ + // RichText.Add(""); + //} + _font = new ExcelTextFontXml(_chart, NameSpaceManager, TopNode, $"{_fontPropertiesPath}/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _font; } @@ -145,12 +148,32 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{_fontPropertiesPath}/a:bodyPr", SchemaNodeOrder); + var defBody = DefaultTextBody; + var firstDefaultRunProperties = DefaultTextBody.Paragraphs.CreateOrGetDefaultRunProperties($"{_defTxBodyPath}/a:p/a:pPr/a:defRPr", TopNode); + _textBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"{_richTextPath}/a:bodyPr", SchemaNodeOrder); + + //Set property without updating xml + _textBody.Paragraphs.FirstDefaultRunProperties = DefaultTextBody.Paragraphs.FirstDefaultRunProperties; } return _textBody; } } - ExcelDrawingTextSettings _textSettings = null; + ExcelTextBody _defaultTextBody = null; + /// + /// Access to default text body properties + /// + public ExcelTextBody DefaultTextBody + { + get + { + if (_defaultTextBody == null) + { + _defaultTextBody = new ExcelTextBody(_chart, NameSpaceManager, TopNode, $"{_defTxBodyPath}/a:bodyPr", SchemaNodeOrder); + } + return _defaultTextBody; + } + } + ExcelDrawingTextSettings _textSettings = null; /// /// Text settings like fills, text outlines and effects /// @@ -160,7 +183,7 @@ public ExcelDrawingTextSettings TextSettings { if (_textSettings == null) { - _textSettings = new ExcelDrawingTextSettings(_chart, NameSpaceManager, TopNode, $"{_fontPropertiesPath}/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + _textSettings = new ExcelDrawingTextSettings(_chart, NameSpaceManager, TopNode, $"{_richTextPath}/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _textSettings; } @@ -224,9 +247,31 @@ internal void CreateRichText() var stylePart = GetStylePart(); if (stylePart != null && stylePart.HasTextRun) { - defFont = Convert.ToSingle(stylePart.DefaultTextRun.FontSize); + defFont = Convert.ToSingle(stylePart.DefaultTextRun.Size); } - _richText = new ExcelParagraphCollection(_chart, NameSpaceManager, TopNode, $"{_fontPropertiesPath}/a:p", SchemaNodeOrder, defFont); + var tb = TextBody; + + //var rtNode = GetNode($"{_richTextPath}"); + //if(rtNode != null) + //{ + // //parent node has been created but it is possible it is without a paragraph node + // //If e.g. a file is read in and ApplyStyles is done before anything else + // var paragraphNode = GetNode($"{_richTextPath}/a:p"); + // if (paragraphNode == null) + // { + // var runProps = tb.Paragraphs.CreateOrGetDefaultRunProperties($"{_richTextPath}/a:p/a:pPr/a:defRPr", TopNode); + // //var newParagraphNode = GetNode($"{_richTextPath}/a:p"); + // tb.Paragraphs.SetPlaceHolderNode(runProps.PathElement.ParentNode.ParentNode); + // } + //} + + _richText = new ExcelParagraphCollection(tb, _chart, NameSpaceManager, TopNode, $"{_richTextPath}/a:p", SchemaNodeOrder, defFont, eTextAlignment.Center); + + //if(tb.Paragraphs.Count == 0) + //{ + // var para = _richText.Add(""); + // _richText.Remove(para); + //} } private ExcelChartStyleEntry GetStylePart() @@ -321,10 +366,10 @@ public double Rotation { get { - var i=GetXmlNodeInt($"{_fontPropertiesPath}/a:bodyPr/@rot"); + var i=GetXmlNodeInt($"{_fontPropertiesPath}/a:bodyPr/@rot", 0); if (i < 0) { - return 360 - (i / 60000); + return 360 + (i / 60000); } else { @@ -363,6 +408,35 @@ void IStyleMandatoryProperties.SetMandatoryProperties() if (Font.Kerning == 0) Font.Kerning = 12; Font.Bold = Font.Bold; //Must be set + //Textbody cannot exist without a paragraph node + if(TextBody.Paragraphs.Count == 0) + { + + var rtNode = GetNode($"{_richTextPath}"); + if (rtNode != null) + { + //parent node has been created but it is possible it is without a paragraph node + //If e.g. a file is read in and ApplyStyles is done before anything else + var paragraphNode = GetNode($"{_richTextPath}/a:p"); + if (paragraphNode == null) + { + var runProps = TextBody.Paragraphs.CreateOrGetDefaultRunProperties($"{_richTextPath}/a:p/a:pPr/a:defRPr", TopNode); + var newParagraphNode = GetNode($"{_richTextPath}/a:p"); + + //This should already have been done but do anyway for safety + TextBody.Paragraphs.FirstDefaultRunProperties = DefaultTextBody.Paragraphs.FirstDefaultRunProperties; + + //The above sets it correctly but it does not update the xml. Update xml manually since we are about to set a text value + var defParaProperties = GetNode($"{_defTxBodyPath}/a:p/a:pPr"); + var newNode = GetNode($"{_richTextPath}/a:p/a:pPr"); + CopyElement((XmlElement)defParaProperties, (XmlElement)newNode); + + TextBody.Paragraphs.SetPlaceHolderNode(newNode.ParentNode); + } + } + TextBody.Paragraphs.Add("Title"); + } + CreatespPrNode($"{_nsPrefix}:spPr"); } } @@ -387,6 +461,16 @@ public override string Text } else { + if(LinkedCell.IsSingleCell == false) + { + string combinedString = ""; + string separator = " "; + foreach(var address in LinkedCell) + { + combinedString += address.Text + separator; + } + return combinedString; + } return LinkedCell.Text; } } @@ -398,6 +482,69 @@ public override string Text CreateRichText(); } var applyStyle = (RichText.Count == 0); + if(applyStyle) + { + var defaultRunPropertiesRich = TextBody.Paragraphs.CreateOrGetDefaultRunProperties($"{_richTextPath}/a:p/a:pPr/a:defRPr", TopNode); + + //This should already have been done but do anyway for safety + TextBody.Paragraphs.FirstDefaultRunProperties = DefaultTextBody.Paragraphs.FirstDefaultRunProperties; + + //The above sets it correctly but it does not update the xml. Update xml manually since we are about to set a text value + var defParaProperties = GetNode($"{_defTxBodyPath}/a:p/a:pPr"); + var newNode = GetNode($"{_richTextPath}/a:p/a:pPr"); + CopyElement((XmlElement)defParaProperties, (XmlElement)newNode); + + TextBody.Paragraphs.SetPlaceHolderNode(newNode.ParentNode); + } + RichText.Text = value; + _font = null; + if (applyStyle) + { + var defRprOld = GetNode($"{_defTxBodyPath}/a:p/a:pPr/a:defRPr"); + defRprOld.InnerXml = ""; + _chart.ApplyStyleOnPart(this, _chart.StyleManager?.Style?.Title, true); + + //re-apply default values + var defParaProperties = GetNode($"{_defTxBodyPath}/a:p/a:pPr"); + var newNode = GetNode($"{_richTextPath}/a:p/a:pPr"); + CopyElement((XmlElement)defParaProperties, (XmlElement)newNode); + } + } + } + /// + /// The text adjusted for the Capitalization property. + /// + public string DisplayedText + { + get + { + if (LinkedCell == null) + { + return RichText.DisplayedText; + } + else + { + if (LinkedCell.IsSingleCell == false) + { + string combinedString = ""; + string separator = " "; + foreach (var address in LinkedCell) + { + combinedString += address.Text + separator; + } + return combinedString; + } + return LinkedCell.Text; + } + } + set + { + if (RichText == null) + { + LinkedCell = null; + CreateRichText(); + } + var applyStyle = (RichText.Count == 0); RichText.Text = value; _font = null; if (applyStyle) _chart.ApplyStyleOnPart(this, _chart.StyleManager?.Style?.Title, true); @@ -459,5 +606,21 @@ public void SetAutoTitle() } internal override bool HasLinkedCell => LinkedCell != null; + + ExcelLayout _layout = null; + /// + /// Contains layout properties, if the title is manually positioned. + /// + public ExcelLayout Layout + { + get + { + if (_layout == null) + { + _layout = new ExcelLayout(NameSpaceManager, TopNode, "c:layout", "", SchemaNodeOrder); + } + return _layout; + } + } } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartTrendline.cs b/src/EPPlus/Drawing/Chart/ExcelChartTrendline.cs index b245bd0fa5..9110c38662 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartTrendline.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartTrendline.cs @@ -10,12 +10,13 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Xml; -using System.Globalization; -using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Style.ThreeD; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; namespace OfficeOpenXml.Drawing.Chart { @@ -34,7 +35,7 @@ internal ExcelChartTrendline(XmlNamespaceManager namespaceManager, XmlNode topNo } const string TRENDLINEPATH = "c:trendlineType/@val"; /// - /// Type of Trendline + /// BulletType of Trendline /// public eTrendLine Type { @@ -278,6 +279,40 @@ void IDrawingStyleBase.CreatespPr() CreatespPrNode(); } + internal string GetName(int index) + { + if(string.IsNullOrEmpty(Name)) + { + var serieName = _serie.GetHeaderText(index); + var trendlineType = GetTypeName(); + + return $"{trendlineType} ({serieName})"; + } + else + { + return Name; + } + } + + private string GetTypeName() + { + switch(Type) + { + case eTrendLine.Exponential: + return "Expon."; + case eTrendLine.Logarithmic: + return "Log."; + case eTrendLine.Polynomial: + return "Poly."; + case eTrendLine.MovingAverage: + return $"{Period} per Mov. Avg."; + case eTrendLine.Power: + return "Power"; + default: + return "Linear"; + } + } + ExcelChartTrendlineLabel _label =null; /// /// Trendline labels @@ -305,5 +340,13 @@ public bool HasLbl (Type != eTrendLine.MovingAverage && (DisplayRSquaredValue == true || DisplayEquation == true)); } } + internal ExcelChartStandardSerie Serie + { + get + { + return _serie; + } + } + } } diff --git a/src/EPPlus/Drawing/Chart/ExcelChartTrendlineLabel.cs b/src/EPPlus/Drawing/Chart/ExcelChartTrendlineLabel.cs index 89ed6052da..594e5c7af2 100644 --- a/src/EPPlus/Drawing/Chart/ExcelChartTrendlineLabel.cs +++ b/src/EPPlus/Drawing/Chart/ExcelChartTrendlineLabel.cs @@ -14,6 +14,7 @@ Date Author Change using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Style.ThreeD; using OfficeOpenXml.Style; +using System; using System.Xml; namespace OfficeOpenXml.Drawing.Chart @@ -23,7 +24,7 @@ namespace OfficeOpenXml.Drawing.Chart /// public class ExcelChartTrendlineLabel : XmlHelper, IDrawingStyle { - ExcelChartStandardSerie _serie; + ExcelChartStandardSerie _serie; internal ExcelChartTrendlineLabel(XmlNamespaceManager namespaceManager, XmlNode topNode, ExcelChartStandardSerie serie) : base(namespaceManager, topNode) { _serie = serie; @@ -71,7 +72,7 @@ public ExcelTextFont Font { if (_font == null) { - _font = new ExcelTextFont(_serie._chart, NameSpaceManager, TopNode, "c:trendlineLbl/c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); + _font = new ExcelTextFontXml(_serie._chart, NameSpaceManager, TopNode, "c:trendlineLbl/c:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder); } return _font; } @@ -86,7 +87,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, "c:trendlineLbl/c:txPr/a:bodyPr", SchemaNodeOrder); + _textBody = new ExcelTextBody(_serie._chart, NameSpaceManager, TopNode, "c:trendlineLbl/c:txPr/a:bodyPr", SchemaNodeOrder); } return _textBody; } @@ -136,7 +137,7 @@ public ExcelParagraphCollection RichText { if (_richText == null) { - _richText = new ExcelParagraphCollection(_serie._chart, NameSpaceManager, TopNode, "c:trendlineLbl/c:tx/c:rich/a:p", SchemaNodeOrder); + _richText = new ExcelParagraphCollection(TextBody, _serie._chart, NameSpaceManager, TopNode, "c:trendlineLbl/c:tx/c:rich/a:p", SchemaNodeOrder); } return _richText; } @@ -168,6 +169,25 @@ public bool SourceLinked { SetXmlNodeBool("c:trendlineLbl/c:numFmt/@sourceLinked", value, true); } - } + } + ExcelLayout _layout = null; + /// + /// Gets the manual layout settings for the trendline label, allowing customization of its position and size + /// within the chart area. + /// + /// Use this property to access and modify the manual layout options for the trendline + /// label, such as its height, width, and position. Changes to these settings affect how the trendline label is + /// displayed in the chart. + public ExcelLayout Layout + { + get + { + if (_layout == null) + { + _layout = new ExcelLayout(NameSpaceManager, TopNode, $"c:trendlineLbl/c:layout", "c:extLst/c:ext[1]/c15:layout", SchemaNodeOrder); + } + return _layout; + } + } } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/Chart/ExcelDoughnutChart.cs b/src/EPPlus/Drawing/Chart/ExcelDoughnutChart.cs index b039b673df..2f3b244c88 100644 --- a/src/EPPlus/Drawing/Chart/ExcelDoughnutChart.cs +++ b/src/EPPlus/Drawing/Chart/ExcelDoughnutChart.cs @@ -43,25 +43,10 @@ internal ExcelDoughnutChart(ExcelChart topChart, XmlNode chartNode, ExcelGroupSh { } - string _firstSliceAngPath = "c:firstSliceAng/@val"; - /// - /// Angle of the first slize - /// - public double FirstSliceAngle - { - get - { - return _chartXmlHelper.GetXmlNodeDouble(_firstSliceAngPath); - } - internal set - { - _chartXmlHelper.SetXmlNodeString(_firstSliceAngPath, value.ToString(CultureInfo.InvariantCulture)); - } - } //string _holeSizePath = "c:chartSpace/c:chart/c:plotArea/{0}/c:holeSize/@val"; string _holeSizePath = "c:holeSize/@val"; /// - /// Size of the doubnut hole + /// FontSize of the doubnut hole /// public double HoleSize { diff --git a/src/EPPlus/Drawing/Chart/ExcelDrawingTextSettings.cs b/src/EPPlus/Drawing/Chart/ExcelDrawingTextSettings.cs index 9545be7711..18ef738b72 100644 --- a/src/EPPlus/Drawing/Chart/ExcelDrawingTextSettings.cs +++ b/src/EPPlus/Drawing/Chart/ExcelDrawingTextSettings.cs @@ -10,9 +10,8 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using OfficeOpenXml.FormulaParsing.Excel.Functions.Finance; -using System.Xml; using OfficeOpenXml.Drawing.Style.Effect; +using System.Xml; namespace OfficeOpenXml.Drawing.Chart { /// diff --git a/src/EPPlus/Drawing/Chart/ExcelLayout.cs b/src/EPPlus/Drawing/Chart/ExcelLayout.cs index dff5841ea8..9b40a956b4 100644 --- a/src/EPPlus/Drawing/Chart/ExcelLayout.cs +++ b/src/EPPlus/Drawing/Chart/ExcelLayout.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Xml; @@ -17,10 +18,20 @@ public class ExcelLayout : XmlHelper /// Manual layout settings for precise control of element position /// public ExcelManualLayout ManualLayout { get; } - + string _path = null; internal ExcelLayout(XmlNamespaceManager ns, XmlNode topNode, string path, string extLstPath, string[] schemaNodeOrder = null) : base(ns, topNode) { + _path = path; ManualLayout = new ExcelManualLayout(ns, topNode, $"{path}/c:manualLayout", $"{extLstPath}/c:manualLayout", schemaNodeOrder); } + internal bool HasLayout + { + get + { + var n = GetNode(_path); + return n != null && (n.Attributes.Count > 0 || n.ChildNodes.Count > 0); + } + } + } } diff --git a/src/EPPlus/Drawing/Chart/ExcelManualLayout.cs b/src/EPPlus/Drawing/Chart/ExcelManualLayout.cs index b02d724910..13299eda3b 100644 --- a/src/EPPlus/Drawing/Chart/ExcelManualLayout.cs +++ b/src/EPPlus/Drawing/Chart/ExcelManualLayout.cs @@ -27,34 +27,33 @@ namespace OfficeOpenXml.Drawing.Chart /// For easiest use it is recommended to not change the modes of width or height. /// Left and Top are used to determine x and y position /// Width and Height to define the width and height of the element. - /// By default all elements originate from their default + /// By default all elements originate from their default position /// Use eLayoutMode.Edge to set origin to the edge of the chart for the relevant element. /// public class ExcelManualLayout : XmlHelper { - //string _layoutTargetPath; - //TODO: Check how this property should be added - ///// - ///// Layout target - ///// - //public eLayoutTarget? LayoutTarget - //{ - // get - // { - // return GetXmlEnumNull(_layoutTargetPath); - // } - // set - // { - // if ( value == null ) - // { - // DeleteNode(_layoutTargetPath, true); - // } - // else - // { - // SetXmlNodeString(_layoutTargetPath, value.ToEnumString()); - // } - // } - //} + string _layoutTargetPath; + /// + /// Layout target + /// + public eLayoutTarget? LayoutTarget + { + get + { + return GetXmlEnumNull(_layoutTargetPath); + } + set + { + if (value == null) + { + DeleteNode(_layoutTargetPath, true); + } + else + { + SetXmlNodeString(_layoutTargetPath, value.ToEnumString()); + } + } + } /// /// Define mode for Left (x) attribute @@ -225,7 +224,7 @@ public double? Height } /// /// Right offset between 100 to -100% of the chart width. In Excel exceeding these values counts as setting the property to 0. - /// Legacy variable. if Height property is set this will be overridden. + /// Legacy variable. if Width property is set this will be overridden. /// public double? LegacyWidth { @@ -265,7 +264,7 @@ public double? LegacyHeight private double? GetXmlValue(string path, string name) { var xmlValue = GetXmlNodeDouble($"{path}/c:{name}/@val"); - return xmlValue == double.NaN ? null : xmlValue * 100; + return double.IsNaN(xmlValue) ? null : xmlValue * 100; } private void SetXmlValue(string path, string name, double? value) @@ -291,10 +290,44 @@ private void SetXmlMode(string path, string name, eLayoutMode value) var aStr = value.ToEnumString(); SetXmlNodeString($"{path}/c:{name}Mode/@val", aStr); } - + internal double GetWidth() + { + if (Width.HasValue && double.IsNaN(Width.Value) == false) + { + return Width.Value; + } + else + { + return LegacyWidth ?? 0D; + } + } + internal double GetHeight() + { + if (Height.HasValue && double.IsNaN(Height.Value) == false) + { + if(HeightMode == eLayoutMode.Edge) + { + return Height.Value - Top.Value; + } + else + { + return Height.Value; + } + } + else + { + if (LegacyHeightMode == eLayoutMode.Edge) + { + return LegacyHeight.Value - Top ?? 0D; + } + else + { + return LegacyHeight ?? 0D; + } + } + } private readonly string _path; private readonly string _extLstPath; - /// /// Manual layout elements /// @@ -302,12 +335,8 @@ internal ExcelManualLayout(XmlNamespaceManager ns, XmlNode topNode, string path, { _path = path; _extLstPath = extLstPath; - //_layoutTargetPath = $"{_path}/c:layoutTarget/@val"; Removed for now. See commented out property LayoutTarget above. - NameSpaceManager.AddNamespace("c15", ExcelPackage.schemaChart2012); - NameSpaceManager.AddNamespace("c16", ExcelPackage.schemaChart2014); - + _layoutTargetPath = path; AddSchemaNodeOrder(schemaNodeOrder, ["layoutTarget", "xMode", "yMode", "wMode", "hMode", "x", "y", "w", "h", "extLst"]); } - } } diff --git a/src/EPPlus/Drawing/Chart/ExcelOfPieChart.cs b/src/EPPlus/Drawing/Chart/ExcelOfPieChart.cs index e6c1b22387..eeec5e5447 100644 --- a/src/EPPlus/Drawing/Chart/ExcelOfPieChart.cs +++ b/src/EPPlus/Drawing/Chart/ExcelOfPieChart.cs @@ -60,7 +60,7 @@ private void SetTypeProperties() const string pieTypePath = "c:ofPieType/@val"; /// - /// Type, pie or bar + /// BulletType, pie or bar /// public ePieType OfPieType { diff --git a/src/EPPlus/Drawing/Chart/ExcelPieChart.cs b/src/EPPlus/Drawing/Chart/ExcelPieChart.cs index 3535aa7ec3..541abfca35 100644 --- a/src/EPPlus/Drawing/Chart/ExcelPieChart.cs +++ b/src/EPPlus/Drawing/Chart/ExcelPieChart.cs @@ -10,11 +10,12 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Table.PivotTable; using System; using System.Collections.Generic; +using System.Globalization; using System.Xml; -using OfficeOpenXml.Drawing.Interfaces; -using OfficeOpenXml.Table.PivotTable; namespace OfficeOpenXml.Drawing.Chart { @@ -101,6 +102,23 @@ internal override eChartType GetChartType(string name) } return base.GetChartType(name); } + + string _firstSliceAngPath = "c:firstSliceAng/@val"; + /// + /// Angle of the first slize + /// + public double FirstSliceAngle + { + get + { + return _chartXmlHelper.GetXmlNodeDouble(_firstSliceAngPath); + } + internal set + { + _chartXmlHelper.SetXmlNodeString(_firstSliceAngPath, value.ToString(CultureInfo.InvariantCulture)); + } + } + /// /// A collection of series for a Pie Chart /// diff --git a/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleEntry.cs b/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleEntry.cs index afbf4434d7..9e6bafd5be 100644 --- a/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleEntry.cs +++ b/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleEntry.cs @@ -17,6 +17,7 @@ Date Author Change using OfficeOpenXml.Drawing.Style.ThreeD; using OfficeOpenXml.Drawing.Interfaces; using OfficeOpenXml.Utils.EnumUtils; +using OfficeOpenXml.Style; namespace OfficeOpenXml.Drawing.Chart.Style { @@ -26,7 +27,7 @@ namespace OfficeOpenXml.Drawing.Chart.Style public class ExcelChartStyleEntry : XmlHelper { string _fillReferencePath = "{0}/{1}:fillRef"; - string _borderReferencePath = "{0}/{1}:lnRef "; + string _borderReferencePath = "{0}/{1}:lnRef"; string _effectReferencePath = "{0}/{1}:effectRef"; string _fontReferencePath = "{0}/{1}:fontRef"; @@ -39,11 +40,12 @@ public class ExcelChartStyleEntry : XmlHelper string _defaultTextRunPath = "{0}/{1}:defRPr"; string _defaultTextBodyPath = "{0}/{1}:bodyPr"; - string _prefix = "cs"; + string _prefix; private readonly IPictureRelationDocument _pictureRelationDocument; - internal ExcelChartStyleEntry(XmlNamespaceManager nsm, XmlNode topNode, string path, IPictureRelationDocument pictureRelationDocument) : base(nsm, topNode) + internal ExcelChartStyleEntry(XmlNamespaceManager nsm, XmlNode topNode, string path, IPictureRelationDocument pictureRelationDocument, string prefix="cs") : base(nsm, topNode) { + _prefix = prefix; SchemaNodeOrder = new string[] { "lnRef", "fillRef", "effectRef", "fontRef", "spPr", "noFill", "solidFill", "blipFill", "gradFill", "noFill", "pattFill","ln", "defRPr" }; _fillReferencePath = string.Format(_fillReferencePath, path, _prefix); _borderReferencePath = string.Format(_borderReferencePath, path, _prefix); @@ -184,17 +186,20 @@ public ExcelDrawing3D ThreeD return _threeD; } } - private ExcelTextRun _defaultTextRun = null; + private ExcelTextFont _defaultTextRun = null; + + string[] SchemaNodeOrderTextRun = new string[] { "ln", "noFill", "solidFill", "gradFill", "pattFill", "blipFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "extLst", "highlight", "kumimoji", "lang", "altLang", "sz", "b", "i", "u", "strike", "kern", "cap", "spc", "normalizeH", "baseline", "noProof", "dirty", "err", "smtClean", "smtId", "bmk" }; + /// /// Reference to default text run settings for a chart part /// - public ExcelTextRun DefaultTextRun + public ExcelTextFont DefaultTextRun { get { if (_defaultTextRun == null) { - _defaultTextRun = new ExcelTextRun(NameSpaceManager, TopNode, _defaultTextRunPath); + _defaultTextRun = new ExcelTextFontXml(_pictureRelationDocument, NameSpaceManager, TopNode, _defaultTextRunPath, SchemaNodeOrderTextRun); } return _defaultTextRun; @@ -210,7 +215,7 @@ public ExcelTextBody DefaultTextBody { if (_defaultTextBody == null) { - _defaultTextBody = new ExcelTextBody(NameSpaceManager, TopNode, _defaultTextBodyPath); + _defaultTextBody = new ExcelTextBody(_pictureRelationDocument, NameSpaceManager, TopNode, _defaultTextBodyPath); } return _defaultTextBody; diff --git a/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleManager.cs b/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleManager.cs index e70e390ce8..558dcad1c2 100644 --- a/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleManager.cs +++ b/src/EPPlus/Drawing/Chart/Style/ExcelChartStyleManager.cs @@ -18,6 +18,7 @@ Date Author Change using OfficeOpenXml.Drawing.Theme; using OfficeOpenXml.Packaging; using OfficeOpenXml.Packaging.Ionic.Zip; +using OfficeOpenXml.Style; using OfficeOpenXml.Utils.FileUtils; using System; using System.Collections.Generic; @@ -867,7 +868,7 @@ private void ApplyStyleFont(ExcelChartStyleEntry section, int indexForColor, IDr } if (section.HasTextRun) { - chartPartWithFont.Font.SetFromXml(section.DefaultTextRun.PathElement); + ((ExcelTextFontXml)chartPartWithFont.Font).SetFromXml(section.DefaultTextRun.PathElement); } if (section.FontReference.HasColor) { diff --git a/src/EPPlus/Drawing/Chart/eAxisLabelAlignment.cs b/src/EPPlus/Drawing/Chart/eAxisLabelAlignment.cs new file mode 100644 index 0000000000..7ecf91a743 --- /dev/null +++ b/src/EPPlus/Drawing/Chart/eAxisLabelAlignment.cs @@ -0,0 +1,33 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 04/22/2020 EPPlus Software AB Added this class + *************************************************************************************************/ +namespace OfficeOpenXml +{ + /// + /// How the axis label should be alignted within the major tickmarks. + /// + public enum eAxisLabelAlignment + { + /// + /// The text shall be centered + /// + Left, + /// + /// The text shall be left justified. + /// + Center, + /// + /// The text shall be right justified. + /// + Right + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Chart/enums/eAxisPosition.cs b/src/EPPlus/Drawing/Chart/enums/eAxisPosition.cs index 0cbcd13295..823243bf3f 100644 --- a/src/EPPlus/Drawing/Chart/enums/eAxisPosition.cs +++ b/src/EPPlus/Drawing/Chart/enums/eAxisPosition.cs @@ -34,4 +34,39 @@ public enum eAxisPosition /// Top = 3 } + public enum eActualAxisPosition + { + /// + /// Left + /// + Left = 0, + /// + /// Bottom + /// + Bottom = 1, + /// + /// Right + /// + Right = 2, + /// + /// Top + /// + Top = 3, + /// + /// If there are two axis on the left side, this is the second axis left (most to the left) + /// + LeftSecond = 5, + /// + /// If there are two axis on the right side, this is the second axis right (most to the right) + /// + RightSecond = 7, + /// + /// If there are two axis on the top, this is the second top left (most to the top) + /// + TopSecond = 9, + /// + /// If there are two axis on the bottom, this is the second bottom left (most to the top) + /// + BottomSecond = 11 + } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/Chart/enums/eAxisType.cs b/src/EPPlus/Drawing/Chart/enums/eAxisType.cs index 18b595a909..bd07c817c2 100644 --- a/src/EPPlus/Drawing/Chart/enums/eAxisType.cs +++ b/src/EPPlus/Drawing/Chart/enums/eAxisType.cs @@ -30,7 +30,7 @@ public enum eAxisType /// Date, /// - /// Series axis (Type of Category axis usually in 3D charts) + /// Series axis (BulletType of Category axis usually in 3D charts) /// Serie } diff --git a/src/EPPlus/Drawing/Chart/enums/eTrendLine.cs b/src/EPPlus/Drawing/Chart/enums/eTrendLine.cs index b32771f3bb..9a41ad6407 100644 --- a/src/EPPlus/Drawing/Chart/enums/eTrendLine.cs +++ b/src/EPPlus/Drawing/Chart/enums/eTrendLine.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing.Chart { /// - /// Type of Trendline for a chart + /// BulletType of Trendline for a chart /// public enum eTrendLine { diff --git a/src/EPPlus/Drawing/Controls/ExcelControl.cs b/src/EPPlus/Drawing/Controls/ExcelControl.cs index eb9d511051..79aae7407b 100644 --- a/src/EPPlus/Drawing/Controls/ExcelControl.cs +++ b/src/EPPlus/Drawing/Controls/ExcelControl.cs @@ -637,7 +637,7 @@ internal virtual void UpdateXml() { fill.Color = color; } - fill.Transparancy = (int)c.Fill.Opacity - 100; + fill.Transparency = (int)c.Fill.Opacity - 100; } } } diff --git a/src/EPPlus/Drawing/Controls/ExcelControlWithText.cs b/src/EPPlus/Drawing/Controls/ExcelControlWithText.cs index 5281cf8669..5b55ba349f 100644 --- a/src/EPPlus/Drawing/Controls/ExcelControlWithText.cs +++ b/src/EPPlus/Drawing/Controls/ExcelControlWithText.cs @@ -87,7 +87,7 @@ public ExcelParagraphCollection RichText { if (_richText == null) { - _richText = new ExcelParagraphCollection(this, NameSpaceManager, TopNode, _paragraphPath, SchemaNodeOrder); + _richText = new ExcelParagraphCollection(TextBody, this, NameSpaceManager, TopNode, _paragraphPath, SchemaNodeOrder); } return _richText; } @@ -117,10 +117,16 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, _textBodyPath, this.SchemaNodeOrder); + _textBody = new ExcelTextBody(_drawings, NameSpaceManager, TopNode, _textBodyPath, this.SchemaNodeOrder); } return _textBody; } } + + internal override void SaveDrawing(bool hasLoadedPivotTables) + { + TextBody.SaveTextBody(); + base.SaveDrawing(hasLoadedPivotTables); + } } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/Controls/enums/eControlType.cs b/src/EPPlus/Drawing/Controls/enums/eControlType.cs index 40c422cf7d..9a43bdff7c 100644 --- a/src/EPPlus/Drawing/Controls/enums/eControlType.cs +++ b/src/EPPlus/Drawing/Controls/enums/eControlType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing.Controls { /// - /// Type of form control + /// BulletType of form control /// public enum eControlType { diff --git a/src/EPPlus/Drawing/EMF/BitMapFileHeader.cs b/src/EPPlus/Drawing/EMF/BitMapFileHeader.cs index 49b182a27e..5ccc8975df 100644 --- a/src/EPPlus/Drawing/EMF/BitMapFileHeader.cs +++ b/src/EPPlus/Drawing/EMF/BitMapFileHeader.cs @@ -41,7 +41,7 @@ internal enum BitMapType : UInt16 } /// - /// Type of bitmap + /// BulletType of bitmap /// internal BitMapType Signature; /// diff --git a/src/EPPlus/Drawing/EMF/Records/EMR_EXTCREATEFONTINDIRECTW.cs b/src/EPPlus/Drawing/EMF/Records/EMR_EXTCREATEFONTINDIRECTW.cs index 833bfc36f0..98ce937ce4 100644 --- a/src/EPPlus/Drawing/EMF/Records/EMR_EXTCREATEFONTINDIRECTW.cs +++ b/src/EPPlus/Drawing/EMF/Records/EMR_EXTCREATEFONTINDIRECTW.cs @@ -36,7 +36,7 @@ internal EMR_EXTCREATEFONTINDIRECTW(BinaryReader br, uint TypeValue) : base(br, ihFonts = br.ReadUInt32(); var sizeOfVariableObject = Size - 12; - if (sizeOfVariableObject > 320)//Size of a LogFontPanose object + if (sizeOfVariableObject > 320)//FontSize of a LogFontPanose object { elw = new LogFontExDv(br); //isExDv = true; @@ -60,7 +60,7 @@ internal EMR_EXTCREATEFONTINDIRECTW(BinaryReader br, uint TypeValue) : base(br, //font.Style = MeasurementFontStyles.Regular; //font.FontFamily = elw.FaceName; - //font.Size = + //font.FontSize = } internal override void WriteBytes(BinaryWriter bw) diff --git a/src/EPPlus/Drawing/EMF/Records/EMR_HEADER.cs b/src/EPPlus/Drawing/EMF/Records/EMR_HEADER.cs index 81555bc9e8..119a1777d7 100644 --- a/src/EPPlus/Drawing/EMF/Records/EMR_HEADER.cs +++ b/src/EPPlus/Drawing/EMF/Records/EMR_HEADER.cs @@ -33,7 +33,7 @@ internal class EMR_HEADER : EMR_RECORD internal byte[] RecordSignature; //4 internal byte[] Version; //4 internal uint Bytes; //4 //Filesize - internal uint Records; //4 //List Size + internal uint Records; //4 //List FontSize internal ushort Handles; //2 //number of graphics objects internal byte[] Reserved; //2 internal uint nDescription; //4 @@ -190,7 +190,7 @@ internal EMR_HEADER(List Records) Handles = 3; foreach (var record in Records) { - //switch (record.Type) + //switch (record.BulletType) //{ // case RECORD_TYPES.EMR_CREATEPEN: // case RECORD_TYPES.EMR_EXTCREATEPEN: diff --git a/src/EPPlus/Drawing/EMF/Records/PlusRecords/EmfPlusRecord.cs b/src/EPPlus/Drawing/EMF/Records/PlusRecords/EmfPlusRecord.cs index ec5bf7187c..4fbae5443f 100644 --- a/src/EPPlus/Drawing/EMF/Records/PlusRecords/EmfPlusRecord.cs +++ b/src/EPPlus/Drawing/EMF/Records/PlusRecords/EmfPlusRecord.cs @@ -16,7 +16,7 @@ internal class EmfPlusRecord /// internal uint Size; //4 /// - /// Size without the Invariant part of given record + /// FontSize without the Invariant part of given record /// internal uint DataSize; //4 internal byte[] data; //This byte array is used for records not yet implemented to preserve data. diff --git a/src/EPPlus/Drawing/Enums/EnumTransl.cs b/src/EPPlus/Drawing/Enums/EnumTransl.cs index d1c66ff1a5..6bc27dcb3c 100644 --- a/src/EPPlus/Drawing/Enums/EnumTransl.cs +++ b/src/EPPlus/Drawing/Enums/EnumTransl.cs @@ -94,34 +94,34 @@ internal static eLineCap ToLineCap(string text) return eLineCap.Flat; } } - internal static eCompundLineStyle ToLineCompound(string s) + internal static eCompoundLineStyle ToLineCompound(string s) { switch (s) { case "dbl": - return eCompundLineStyle.Double; - case "sng": - return eCompundLineStyle.Single; + return eCompoundLineStyle.Double; case "thickThin": - return eCompundLineStyle.DoubleThickThin; + return eCompoundLineStyle.DoubleThickThin; case "thinThick": - return eCompundLineStyle.DoubleThinThick; + return eCompoundLineStyle.DoubleThinThick; + case "tri": + return eCompoundLineStyle.TripleThinThickThin; default: - return eCompundLineStyle.TripleThinThickThin; + return eCompoundLineStyle.Single; } } - internal static string FromLineCompound(eCompundLineStyle v) + internal static string FromLineCompound(eCompoundLineStyle v) { switch (v) { - case eCompundLineStyle.Double: + case eCompoundLineStyle.Double: return "dbl"; - case eCompundLineStyle.Single: + case eCompoundLineStyle.Single: return "sng"; - case eCompundLineStyle.DoubleThickThin: + case eCompoundLineStyle.DoubleThickThin: return "thickThin"; - case eCompundLineStyle.DoubleThinThick: + case eCompoundLineStyle.DoubleThinThick: return "thinThick"; default: return "tri"; diff --git a/src/EPPlus/Drawing/Enums/eCompundLineStyle.cs b/src/EPPlus/Drawing/Enums/eCompoundLineStyle.cs similarity index 97% rename from src/EPPlus/Drawing/Enums/eCompundLineStyle.cs rename to src/EPPlus/Drawing/Enums/eCompoundLineStyle.cs index 468ec03c2b..21d71d19cc 100644 --- a/src/EPPlus/Drawing/Enums/eCompundLineStyle.cs +++ b/src/EPPlus/Drawing/Enums/eCompoundLineStyle.cs @@ -15,7 +15,7 @@ namespace OfficeOpenXml.Drawing /// /// The compound line type. Used for underlining text /// - public enum eCompundLineStyle + public enum eCompoundLineStyle { /// /// Double lines with equal width diff --git a/src/EPPlus/Drawing/Enums/eDrawingType.cs b/src/EPPlus/Drawing/Enums/eDrawingType.cs index 581d6e12d2..5c54901d75 100644 --- a/src/EPPlus/Drawing/Enums/eDrawingType.cs +++ b/src/EPPlus/Drawing/Enums/eDrawingType.cs @@ -18,7 +18,7 @@ public enum eDrawingType /// Shape, /// - /// A Picture drawing + /// A Blip drawing /// Picture, /// diff --git a/src/EPPlus/Drawing/Enums/eFontType.cs b/src/EPPlus/Drawing/Enums/eFontType.cs index 162c2e0d9f..ea7e103437 100644 --- a/src/EPPlus/Drawing/Enums/eFontType.cs +++ b/src/EPPlus/Drawing/Enums/eFontType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing { /// - /// Type of font + /// BulletType of font /// public enum eFontType { diff --git a/src/EPPlus/Drawing/Enums/eLineCap.cs b/src/EPPlus/Drawing/Enums/eLineCap.cs index 587650d2df..699d98a59e 100644 --- a/src/EPPlus/Drawing/Enums/eLineCap.cs +++ b/src/EPPlus/Drawing/Enums/eLineCap.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing { /// - /// The Type of Line cap + /// The BulletType of Line cap /// public enum eLineCap { diff --git a/src/EPPlus/Drawing/Enums/eSchemeColor.cs b/src/EPPlus/Drawing/Enums/eSchemeColor.cs index fd51e80a13..adedcb5bff 100644 --- a/src/EPPlus/Drawing/Enums/eSchemeColor.cs +++ b/src/EPPlus/Drawing/Enums/eSchemeColor.cs @@ -66,6 +66,7 @@ public enum eSchemeColor /// FollowedHyperlink, /// + /// AKA "phClr" /// A color used in theme definitions which means to use the color of the style /// Style, diff --git a/src/EPPlus/Drawing/Enums/eShapeStyle.cs b/src/EPPlus/Drawing/Enums/eShapeStyle.cs index b0ef7ad41f..8bfef40a95 100644 --- a/src/EPPlus/Drawing/Enums/eShapeStyle.cs +++ b/src/EPPlus/Drawing/Enums/eShapeStyle.cs @@ -46,7 +46,7 @@ public enum eShapeStyle /// ActionButtonBackPrevious, /// - /// Action button: Begining |< + /// Action button: Beginning |< /// ActionButtonBeginning, /// @@ -170,7 +170,7 @@ public enum eShapeStyle /// ChartStar, /// - /// A x within a rectagle + /// A x within a rectangle /// ChartX, /// @@ -198,7 +198,7 @@ public enum eShapeStyle /// Corner, /// - /// Cornder Tabs: Triangle in the corners. + /// Corner Tabs: Triangle in the corners. /// CornerTabs, /// @@ -274,11 +274,11 @@ public enum eShapeStyle /// Ellipse, /// - /// Elipse ribbon: point up + /// Ellipse ribbon: point up /// EllipseRibbon, /// - /// Elipse ribbon: point down + /// Ellipse ribbon: point down /// EllipseRibbon2, /// @@ -346,7 +346,7 @@ public enum eShapeStyle /// FlowChartMerge, /// - /// Flow chart: Multidocument + /// Flow chart: Multi document /// FlowChartMultidocument, /// @@ -474,7 +474,7 @@ public enum eShapeStyle /// LeftRightArrow, /// - /// Callout: Left rigth arrow + /// Callout: Left rightd arrow /// LeftRightArrowCallout, /// @@ -764,6 +764,10 @@ public enum eShapeStyle /// /// Vertical scroll /// - VerticalScroll + VerticalScroll, + /// + /// This is a custom shape defined by in the + /// + CustomShape } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/ExcelChartDrawings.cs b/src/EPPlus/Drawing/ExcelChartDrawings.cs index 2bd1acf7e8..7d59a3d23e 100644 --- a/src/EPPlus/Drawing/ExcelChartDrawings.cs +++ b/src/EPPlus/Drawing/ExcelChartDrawings.cs @@ -37,7 +37,6 @@ internal ExcelChartDrawings(ExcelChartStandard chart) _chart = chart; LoadDrawings(chart); } - internal void LoadDrawings(ExcelChartStandard chart) { if (_drawings == null) diff --git a/src/EPPlus/Drawing/ExcelDrawing.cs b/src/EPPlus/Drawing/ExcelDrawing.cs index 08fe0167ff..6f3713f655 100644 --- a/src/EPPlus/Drawing/ExcelDrawing.cs +++ b/src/EPPlus/Drawing/ExcelDrawing.cs @@ -10,15 +10,23 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Export.Utils; +using EPPlusImageRenderer; +using OfficeOpenXml.ConditionalFormatting; using OfficeOpenXml.Core.Worksheet; using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Drawing.Controls; using OfficeOpenXml.Drawing.OleObject; using OfficeOpenXml.Drawing.Slicer; +using OfficeOpenXml.Export.HtmlExport; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils.Drawings; using OfficeOpenXml.Utils.EnumUtils; using OfficeOpenXml.Utils.FileUtils; +using OfficeOpenXml.Utils.TypeConversion; using OfficeOpenXml.Utils.XML; using System; using System.Collections.Generic; @@ -27,6 +35,7 @@ Date Author Change using System.Linq; using System.Text; using System.Xml; +using static Microsoft.IO.RecyclableMemoryStreamManager; namespace OfficeOpenXml.Drawing { @@ -55,7 +64,7 @@ public class ExcelDrawing : XmlHelper, IDisposable /// public const int EMU_PER_CM = 360000; /// - /// The ratio between EMU and milimeters + /// The ratio between EMU and millimeters /// public const int EMU_PER_MM = 3600000; /// @@ -131,10 +140,15 @@ internal ExcelDrawing(ExcelDrawings drawings, XmlNode node, string topPath, stri SetPositionProperties(drawings, node); GetPositionSize(); //Get the drawing position and size, so we can adjust it upon save, if the normal font is changed } + var custGeomNode = GetNode("xdr:sp/xdr:spPr/a:custGeom"); + if(custGeomNode!=null) + { + CustomGeom = new ExcelDrawingCustomGeometry(this, NameSpaceManager, custGeomNode); + } if (DrawingType == eDrawingType.Control || DrawingType == eDrawingType.OleObject || drawings._nextDrawingId >= 1025) { _id = drawings.Worksheet._nextControlId++; - } + } } internal virtual void AdjustXPathsForGrouping(bool group) @@ -1363,7 +1377,12 @@ public void ChangeCellAnchor(eEditAs type) SetPixelWidth(width); SetPixelHeight(height); } - + public void GetSizeInPixels(out int width, out int height) + { + GetPositionSize(); + width = (int)_width; + height = (int)_height; + } private void ChangeCellAnchorTypeInternal(eEditAs type) { if (type != CellAnchor) @@ -1737,6 +1756,9 @@ public ExcelGroupShape ParentGroup return _parent; } } + + internal ExcelDrawingCustomGeometry CustomGeom { get; private set; } + internal virtual void DeleteMe() { TopNode.ParentNode.RemoveChild(TopNode); @@ -2246,7 +2268,7 @@ private XmlNode CopyOleObject(ExcelWorksheet worksheet, int row, int col, int ro newNode = oleNode.OwnerDocument.ImportNode(ole._oleObject.TopNode.ParentNode.ParentNode, true); } oleNode.AppendChild(newNode); - //Copy OleObject & Image + //Copy OleObject & BulletImage var shapeId = WorksheetCopyHelper.CopyOleObject(worksheet._package, worksheet, ole, worksheet._drawings.DrawingXml); if (!isGroupShape) @@ -2562,6 +2584,46 @@ internal ExcelAddressBase GetAddress() internal virtual void SaveDrawing(bool hasLoadedPivotTables) { //Individual drawings that require certain saving actions do so by overriding this + + } + /// + /// Converts the drawing to a SVG image. + /// This is currently only supported for shapes, line-, column-, bar- and pie- charts. + /// + /// The svg image. + /// If the drawing type is not supported + public string ToSvg() + { + return ToSvg(null); } + /// git statu + /// Converts the drawing to a SVG image. + /// This is currently only supported for shapes, line-, column-, bar- and pie- charts. + /// + /// + /// The svg image. + /// If the drawing type is not supported + public string ToSvg(Action options) + { + var o = new SvgRenderOptions(); + if(options != null) options.Invoke(o); + if (this.DrawingType == eDrawingType.Shape) + { + return ((ExcelShape)this).ToSvg(o); + } + else if (this.DrawingType == eDrawingType.Chart) + { + var cr = new ChartRenderer((ExcelChart)this, o); + + var sb = new StringBuilder(); + + var shapeRenderer = new SvgShapeRenderer(this.GetBoundingBox(), sb, o); + shapeRenderer.Render(cr.RenderItems); + + return sb.ToString(); + } + throw new NotSupportedException("Only line-, column-, bar- and pie charts and shapes can be rendered to svg"); + } + } } diff --git a/src/EPPlus/Drawing/ExcelDrawingBorder.cs b/src/EPPlus/Drawing/ExcelDrawingBorder.cs index 02a5ad78b2..f9c749bfed 100644 --- a/src/EPPlus/Drawing/ExcelDrawingBorder.cs +++ b/src/EPPlus/Drawing/ExcelDrawingBorder.cs @@ -69,7 +69,7 @@ public eLineStyle? LineStyle get { var v = GetXmlNodeString(_lineStylePath); - if (string.IsNullOrEmpty(v)) + if (string.IsNullOrEmpty(v)) { return null; } @@ -110,7 +110,7 @@ private void InitSpPr() /// /// The compound line type that is to be used for lines with text such as underlines /// - public eCompundLineStyle CompoundLineStyle + public eCompoundLineStyle CompoundLineStyle { get { diff --git a/src/EPPlus/Drawing/ExcelDrawingCustomGeometry.cs b/src/EPPlus/Drawing/ExcelDrawingCustomGeometry.cs new file mode 100644 index 0000000000..7d6f5adf99 --- /dev/null +++ b/src/EPPlus/Drawing/ExcelDrawingCustomGeometry.cs @@ -0,0 +1,40 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.ShapeDefinitions; +using System.Collections.Generic; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + internal class ExcelDrawingCustomGeometry : XmlHelper + { + ExcelDrawing _drawing; + internal ExcelDrawingCustomGeometry(ExcelDrawing drawing, XmlNamespaceManager nameSpaceManager, XmlNode topNode) : base(nameSpaceManager, topNode) + { + _drawing = drawing; + var pathNode = GetNode("a:pathLst"); + if (pathNode != null) + { + foreach (var cn in pathNode.ChildNodes) + { + if (cn is XmlElement e) + { + DrawingPaths.Add(new DrawingPath(e, NameSpaceManager)); + } + } + } + } + internal List DrawingPaths { get; } = new List(); + + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/ExcelDrawingFill.cs b/src/EPPlus/Drawing/ExcelDrawingFill.cs index 6896b9dea9..9ece8958d7 100644 --- a/src/EPPlus/Drawing/ExcelDrawingFill.cs +++ b/src/EPPlus/Drawing/ExcelDrawingFill.cs @@ -119,7 +119,7 @@ internal override void BeforeSave() private ExcelDrawingPatternFill _patternFill = null; /// /// Reference pattern fill properties - /// This property is only accessable when Type is set to PatternFill + /// This property is only accessable when BulletType is set to PatternFill /// public ExcelDrawingPatternFill PatternFill { @@ -131,7 +131,7 @@ public ExcelDrawingPatternFill PatternFill private ExcelDrawingBlipFill _blipFill = null; /// /// Reference gradient fill properties - /// This property is only accessable when Type is set to BlipFill + /// This property is only accessable when BulletType is set to BlipFill /// public ExcelDrawingBlipFill BlipFill { diff --git a/src/EPPlus/Drawing/ExcelDrawingFillBasic.cs b/src/EPPlus/Drawing/ExcelDrawingFillBasic.cs index 3e558105f2..da9f1d1a7b 100644 --- a/src/EPPlus/Drawing/ExcelDrawingFillBasic.cs +++ b/src/EPPlus/Drawing/ExcelDrawingFillBasic.cs @@ -33,14 +33,11 @@ public class ExcelDrawingFillBasic : XmlHelper, IDisposable /// internal protected XmlNode _fillNode; /// - /// The drawings collection - /// - internal protected ExcelDrawing _drawing; - /// /// The fill type node. /// internal protected XmlNode _fillTypeNode = null; internal Action _initXml; + ExcelPackage _package; internal ExcelDrawingFillBasic(ExcelPackage pck, XmlNamespaceManager nameSpaceManager, XmlNode topNode, string fillPath, string[] schemaNodeOrderBefore, bool doLoad, Action initXml = null) : base(nameSpaceManager, topNode) { @@ -53,6 +50,7 @@ internal ExcelDrawingFillBasic(ExcelPackage pck, XmlNamespaceManager nameSpaceMa { LoadFill(); } + _package = pck; if (pck != null) { pck.BeforeSave.Add(BeforeSave); @@ -144,7 +142,13 @@ private void CreateImageRelation(ExcelDrawingFill fill, XmlElement copyFromFillE IPictureContainer pic = fill.BlipFill; } - + internal bool IsEmpty + { + get + { + return _fillTypeNode==null; + } + } internal string GetFromXml() { return _fillTypeNode.OuterXml; @@ -242,16 +246,18 @@ public eFillStyle Style /// /// Fill color for solid fills. /// Other fill styles will return Color.Empty. - /// Setting this propery will set the Type to SolidFill with the specified color. + /// Setting this propery will set the Style to SolidFill with the specified color. /// public Color Color { get - { + { if (Style != eFillStyle.SolidFill) return Color.Empty; - if (SolidFill.Color.ColorType != eDrawingColorType.Rgb) return Color.Empty; - var col = SolidFill.Color.RgbColor.Color; - if(col == Color.Empty) + //if (SolidFill.Color.ColorType != eDrawingColorType.Rgb) return Color.Empty; + + //var col = SolidFill.Color.RgbColor.Color; + var col = Utils.TypeConversion.ColorConverter.GetThemeColor(_package.Workbook.ThemeManager.GetOrCreateTheme(), SolidFill.Color); + if (col == Color.Empty) { return Color.FromArgb(79, 129, 189); } @@ -271,7 +277,7 @@ public Color Color /// /// Reference solid fill properties - /// This property is only accessable when Type is set to SolidFill + /// This property is only accessable when BulletType is set to SolidFill /// public ExcelDrawingSolidFill SolidFill { @@ -287,7 +293,7 @@ public ExcelDrawingSolidFill SolidFill private ExcelDrawingGradientFill _gradientFill = null; /// /// Reference gradient fill properties - /// This property is only accessable when Type is set to GradientFill + /// This property is only accessable when BulletType is set to GradientFill /// public ExcelDrawingGradientFill GradientFill { @@ -297,10 +303,10 @@ public ExcelDrawingGradientFill GradientFill } } /// - /// Transparancy in percent from a solid fill. + /// Transparency in percent from a solid fill. /// This is the same as 100-Fill.Transform.Alpha /// - public int Transparancy + public int Transparency { get { diff --git a/src/EPPlus/Drawing/ExcelDrawingRectangle.cs b/src/EPPlus/Drawing/ExcelDrawingRectangle.cs index aad12bc248..7f1a2c59c4 100644 --- a/src/EPPlus/Drawing/ExcelDrawingRectangle.cs +++ b/src/EPPlus/Drawing/ExcelDrawingRectangle.cs @@ -10,6 +10,9 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using System; + namespace OfficeOpenXml.Drawing.Theme { /// diff --git a/src/EPPlus/Drawing/ExcelDrawings.cs b/src/EPPlus/Drawing/ExcelDrawings.cs index 3f200ec907..ddbfe85fec 100644 --- a/src/EPPlus/Drawing/ExcelDrawings.cs +++ b/src/EPPlus/Drawing/ExcelDrawings.cs @@ -91,7 +91,13 @@ internal ExcelDrawings(ExcelPackage xlPackage, ExcelWorksheet sheet) Worksheet = sheet; _drawingsXml = new XmlDocument(); + + //NOTE: PreserveWhitespace MUST be true because of case #2201 + //see: https://github.com/EPPlusSoftware/EPPlus/issues/2201 + //see: DrawingIssues.cs EnsureWhiteSpaceIsPreservedInShapes + //Alternative solution: Exclude content of from _drawingsXml.PreserveWhitespace false somehow _drawingsXml.PreserveWhitespace = true; + _drawingsList = new List(); _drawingNames = new Dictionary(StringComparer.OrdinalIgnoreCase); CreateNSM(); @@ -250,6 +256,8 @@ private void CreateNSM() NameSpaceManager.AddNamespace("sle15", ExcelPackage.schemaSlicer); NameSpaceManager.AddNamespace("a14", ExcelPackage.schemaDrawings2010); NameSpaceManager.AddNamespace("asvg", "http://schemas.microsoft.com/office/drawing/2016/SVG/main"); + NameSpaceManager.AddNamespace("c15", ExcelPackage.schemaChart2012); + NameSpaceManager.AddNamespace("c16", ExcelPackage.schemaChart2014); } private void CreateChartNSM() { @@ -358,7 +366,7 @@ internal Uri UriDrawing /// Stock charts cannot be added by this method. See /// /// - /// Type of chart + /// BulletType of chart /// The pivot table source for a pivot chart /// The top element drawing type. Default is OneCellAnchor for Pictures and TwoCellAnchor from Charts and Shapes /// The chart @@ -404,7 +412,7 @@ internal ExcelChart AddAllChartTypes(string Name, eChartType ChartType, ExcelPiv /// Do not support Stock charts . /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelChart AddChart(string Name, eChartType ChartType) { @@ -414,7 +422,7 @@ public ExcelChart AddChart(string Name, eChartType ChartType) /// Adds a new chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelChartEx AddExtendedChart(string Name, eChartExType ChartType) { @@ -490,7 +498,7 @@ public ExcelRegionMapChart AddRegionMapChart(string Name) /// Extended charts are /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelChartEx AddExtendedChart(string Name, eChartExType ChartType, ExcelPivotTable PivotTableSource) @@ -727,7 +735,7 @@ private void ValidateSeries(ExcelRangeBase CategorySerie, ExcelRangeBase HighSer /// Add a new linechart to the worksheet. /// /// - /// Type of linechart + /// BulletType of linechart /// The chart public ExcelLineChart AddLineChart(string Name, eLineChartType ChartType) { @@ -737,7 +745,7 @@ public ExcelLineChart AddLineChart(string Name, eLineChartType ChartType) /// Adds a new linechart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelLineChart AddLineChart(string Name, eLineChartType ChartType, ExcelPivotTable PivotTableSource) @@ -748,7 +756,7 @@ public ExcelLineChart AddLineChart(string Name, eLineChartType ChartType, ExcelP /// Add a new area chart to the worksheet. /// /// - /// Type of linechart + /// BulletType of linechart /// The chart public ExcelAreaChart AddAreaChart(string Name, eAreaChartType ChartType) { @@ -758,7 +766,7 @@ public ExcelAreaChart AddAreaChart(string Name, eAreaChartType ChartType) /// Adds a new area chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelAreaChart AddAreaChart(string Name, eAreaChartType ChartType, ExcelPivotTable PivotTableSource) @@ -769,7 +777,7 @@ public ExcelAreaChart AddAreaChart(string Name, eAreaChartType ChartType, ExcelP /// Adds a new barchart to the worksheet. /// /// - /// Type of linechart + /// BulletType of linechart /// The chart public ExcelBarChart AddBarChart(string Name, eBarChartType ChartType) { @@ -779,7 +787,7 @@ public ExcelBarChart AddBarChart(string Name, eBarChartType ChartType) /// Adds a new column- or bar- chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelBarChart AddBarChart(string Name, eBarChartType ChartType, ExcelPivotTable PivotTableSource) @@ -790,7 +798,7 @@ public ExcelBarChart AddBarChart(string Name, eBarChartType ChartType, ExcelPivo /// Adds a new pie chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelPieChart AddPieChart(string Name, ePieChartType ChartType) { @@ -800,7 +808,7 @@ public ExcelPieChart AddPieChart(string Name, ePieChartType ChartType) /// Adds a new pie chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelPieChart AddPieChart(string Name, ePieChartType ChartType, ExcelPivotTable PivotTableSource) @@ -811,7 +819,7 @@ public ExcelPieChart AddPieChart(string Name, ePieChartType ChartType, ExcelPivo /// Adds a new doughnut chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelDoughnutChart AddDoughnutChart(string Name, eDoughnutChartType ChartType, ExcelPivotTable PivotTableSource) @@ -822,7 +830,7 @@ public ExcelDoughnutChart AddDoughnutChart(string Name, eDoughnutChartType Chart /// Adds a new doughnut chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelDoughnutChart AddDoughnutChart(string Name, eDoughnutChartType ChartType) { @@ -832,7 +840,7 @@ public ExcelDoughnutChart AddDoughnutChart(string Name, eDoughnutChartType Chart /// Adds a new line chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelOfPieChart AddOfPieChart(string Name, eOfPieChartType ChartType) { @@ -842,7 +850,7 @@ public ExcelOfPieChart AddOfPieChart(string Name, eOfPieChartType ChartType) /// Add a new pie of pie or bar of pie chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelOfPieChart AddOfPieChart(string Name, eOfPieChartType ChartType, ExcelPivotTable PivotTableSource) @@ -853,7 +861,7 @@ public ExcelOfPieChart AddOfPieChart(string Name, eOfPieChartType ChartType, Exc /// Adds a new bubble chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelBubbleChart AddBubbleChart(string Name, eBubbleChartType ChartType) { @@ -863,7 +871,7 @@ public ExcelBubbleChart AddBubbleChart(string Name, eBubbleChartType ChartType) /// Adds a new bubble chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelBubbleChart AddBubbleChart(string Name, eBubbleChartType ChartType, ExcelPivotTable PivotTableSource) @@ -874,7 +882,7 @@ public ExcelBubbleChart AddBubbleChart(string Name, eBubbleChartType ChartType, /// Adds a new scatter chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelScatterChart AddScatterChart(string Name, eScatterChartType ChartType, ExcelPivotTable PivotTableSource) @@ -885,7 +893,7 @@ public ExcelScatterChart AddScatterChart(string Name, eScatterChartType ChartTyp /// Adds a new scatter chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelScatterChart AddScatterChart(string Name, eScatterChartType ChartType) { @@ -895,7 +903,7 @@ public ExcelScatterChart AddScatterChart(string Name, eScatterChartType ChartTyp /// Adds a new radar chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelRadarChart AddRadarChart(string Name, eRadarChartType ChartType, ExcelPivotTable PivotTableSource) @@ -906,7 +914,7 @@ public ExcelRadarChart AddRadarChart(string Name, eRadarChartType ChartType, Exc /// Adds a new radar chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelRadarChart AddRadarChart(string Name, eRadarChartType ChartType) { @@ -916,7 +924,7 @@ public ExcelRadarChart AddRadarChart(string Name, eRadarChartType ChartType) /// Adds a new surface chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The pivottable source for a pivotchart /// The chart public ExcelSurfaceChart AddSurfaceChart(string Name, eSurfaceChartType ChartType, ExcelPivotTable PivotTableSource) @@ -927,7 +935,7 @@ public ExcelSurfaceChart AddSurfaceChart(string Name, eSurfaceChartType ChartTyp /// Adds a new surface chart to the worksheet. /// /// - /// Type of chart + /// BulletType of chart /// The chart public ExcelSurfaceChart AddSurfaceChart(string Name, eSurfaceChartType ChartType) { @@ -971,7 +979,7 @@ public ExcelPicture AddPicture(string Name, string ImagePath, PictureLocation Lo /// /// The name of the drawing object /// The path to the image file - /// Picture Hyperlink + /// Blip Hyperlink /// Location to access the image from /// A picture object public ExcelPicture AddPicture(string Name, string ImagePath, ExcelHyperLink Hyperlink, PictureLocation Location = PictureLocation.Embed) @@ -1044,7 +1052,7 @@ public ExcelPicture AddPicture(string Name, Stream PictureStream) /// /// /// An stream image. - /// The Picture Hyperlink + /// The Blip Hyperlink /// A picture object public ExcelPicture AddPicture(string Name, Stream PictureStream, Uri Hyperlink) { @@ -1122,7 +1130,7 @@ public async Task AddPictureAsync(string Name, FileInfo ImageFile, /// /// /// The image file - /// Picture Hyperlink + /// Blip Hyperlink /// Location to access the image from /// A picture object public async Task AddPictureAsync(string Name, FileInfo ImageFile, Uri Hyperlink, PictureLocation Location = PictureLocation.Embed) @@ -1158,7 +1166,7 @@ public async Task AddPictureAsync(string Name, string ImagePath, P /// /// /// The path to the image file - /// Picture Hyperlink + /// Blip Hyperlink /// Location to access the image from /// A picture object public async Task AddPictureAsync(string Name, string ImagePath, Uri Hyperlink, PictureLocation Location = PictureLocation.Embed) @@ -1181,7 +1189,7 @@ public async Task AddPictureAsync(string Name, Stream PictureStrea /// /// /// An stream image. - /// The Picture Hyperlink + /// The Blip Hyperlink /// A picture object public async Task AddPictureAsync(string Name, Stream PictureStream, Uri Hyperlink) { @@ -2126,25 +2134,13 @@ internal ExcelDrawing GetById(int id) return null; } - /// - /// Read the drawings coordinates, height and width. - /// - internal void ReadPositionsAndSize() - { - foreach (var d in _drawingsList) - { - d.GetPositionSize(); - } - } - - internal void SaveDrawings(bool hasLoadedPivotTables) { if (UriDrawing != null) { if (Count == 0) { - if (Worksheet != null) + if(Worksheet != null) { Worksheet.Part.DeleteRelationship(_drawingRelation.Id); Worksheet._package.ZipPackage.DeletePart(UriDrawing); @@ -2170,5 +2166,16 @@ internal void SaveDrawings(bool hasLoadedPivotTables) } } } + + /// + /// Read the drawings coordinates, height and width. + /// + internal void ReadPositionsAndSize() + { + foreach (var d in _drawingsList) + { + d.GetPositionSize(); + } + } } } diff --git a/src/EPPlus/Drawing/ExcelGroupShape.cs b/src/EPPlus/Drawing/ExcelGroupShape.cs index 7083900510..9cb0fc47c1 100644 --- a/src/EPPlus/Drawing/ExcelGroupShape.cs +++ b/src/EPPlus/Drawing/ExcelGroupShape.cs @@ -665,5 +665,4 @@ internal override void SaveDrawing(bool hasLoadedPivotTables) } } } - } \ No newline at end of file diff --git a/src/EPPlus/Drawing/ExcelImage.cs b/src/EPPlus/Drawing/ExcelImage.cs index 4ca36e46f2..8cc4af39d0 100644 --- a/src/EPPlus/Drawing/ExcelImage.cs +++ b/src/EPPlus/Drawing/ExcelImage.cs @@ -58,9 +58,16 @@ public ExcelImage(FileInfo imageFile) /// /// The stream containing the image /// The type of image loaded in the stream - public ExcelImage(Stream imageStream, ePictureType pictureType) + public ExcelImage(Stream imageStream, ePictureType? pictureType=null) { - SetImage(imageStream, pictureType); + if (pictureType.HasValue) + { + SetImage(imageStream, pictureType.Value); + } + else + { + SetImage(imageStream); + } } /// /// Creates an ExcelImage to be used as template for adding images. @@ -131,6 +138,41 @@ public ExcelImage SetImage(ExcelImage image) SetImage(image.ImageBytes, image.Type.Value, true); return this; } + /// + /// Sets a new image. + /// + /// The stream containing the image. + public ExcelImage SetImage(Stream imageStream) + { + MemoryStream ms; + if (imageStream is MemoryStream tms) + { + ms = tms; + } + else + { + if (imageStream.CanRead == false || imageStream.CanSeek == false) + { + throw (new ArgumentException("Stream must be readable and seekable", nameof(imageStream))); + } + var byRet = new byte[imageStream.Length]; + imageStream.Seek(0, SeekOrigin.Begin); + var r = imageStream.Read(byRet, 0, (int)imageStream.Length); + ms = new MemoryStream(byRet); + } + + var pictureType = ImageReader.GetPictureType(ms, true); + if (pictureType.HasValue) + { + SetImage(ms.ToArray(), pictureType.Value, true); + } + else + { + throw new InvalidDataException("Supplied Stream is not in a valid image format."); + } + + return this; + } /// /// Sets a new image. @@ -147,7 +189,7 @@ public ExcelImage SetImage(Stream imageStream, ePictureType pictureType) { if(imageStream.CanRead ==false || imageStream.CanSeek == false) { - throw (new ArgumentException("Stream must be readable and seekble", nameof(imageStream))); + throw (new ArgumentException("Stream must be readable and seekable", nameof(imageStream))); } var byRet = new byte[imageStream.Length]; imageStream.Seek(0, SeekOrigin.Begin); @@ -173,7 +215,7 @@ public async Task SetImageAsync(Stream imageStream, ePictureType pic { if (imageStream.CanRead == false || imageStream.CanSeek == false) { - throw (new ArgumentException("Stream must be readable and seekble", nameof(imageStream))); + throw (new ArgumentException("Stream must be readable and seekable", nameof(imageStream))); } var byRet = new byte[imageStream.Length]; imageStream.Seek(0, SeekOrigin.Begin); diff --git a/src/EPPlus/Drawing/ExcelPicture.cs b/src/EPPlus/Drawing/ExcelPicture.cs index bfa57a5124..aeecc7c3b0 100644 --- a/src/EPPlus/Drawing/ExcelPicture.cs +++ b/src/EPPlus/Drawing/ExcelPicture.cs @@ -23,10 +23,6 @@ Date Author Change using OfficeOpenXml.Utils.Image; using OfficeOpenXml.Utils.FileUtils; - -#if NETFULL -using System.Drawing.Imaging; -#endif #if !NET35 && !NET40 using System.Threading.Tasks; #endif @@ -325,8 +321,8 @@ internal void RecalcWidthHeight() SetSize((int)width, (int)height); } - //Image.Bounds.Height = origHeight; - //Image.Bounds.Width = origWidth; + //BulletImage.Bounds.Height = origHeight; + //BulletImage.Bounds.Width = origWidth; } } diff --git a/src/EPPlus/Drawing/ExcelShape.cs b/src/EPPlus/Drawing/ExcelShape.cs index 0d0fe50131..a224eab0de 100644 --- a/src/EPPlus/Drawing/ExcelShape.cs +++ b/src/EPPlus/Drawing/ExcelShape.cs @@ -10,9 +10,16 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Export.Utils; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Renderer; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using System; using System.Text; using System.Xml; -using OfficeOpenXml.Drawing.Interfaces; +using static Microsoft.IO.RecyclableMemoryStreamManager; namespace OfficeOpenXml.Drawing { /// @@ -75,7 +82,7 @@ internal ExcelShape(ExcelDrawings drawings, XmlNode node, eShapeStyle style, Dra private string ShapeStartXml() { StringBuilder xml = new StringBuilder(); - xml.AppendFormat("<{2}:nvSpPr><{2}:cNvPr id=\"{0}\" name=\"{1}\" /><{2}:cNvSpPr /><{2}:spPr><{2}:style><{2}:txBody>", Id, Name, NamespacePrefixes[(int)_drawings._collectionType]); + xml.AppendFormat("<{2}:nvSpPr><{2}:cNvPr id=\"{0}\" name=\"{1}\" /><{2}:cNvSpPr /><{2}:spPr><{2}:style><{2}:txBody>", Id, Name, NamespacePrefixes[(int)_drawings._collectionType]); return xml.ToString(); } @@ -89,5 +96,13 @@ internal override void DeleteMe() } base.DeleteMe(); } + public string ToSvg(SvgRenderOptions options) + { + var sr = new ShapeRenderer(this); + var sb = new StringBuilder(); + var svg = new SvgShapeRenderer(this.GetBoundingBox(), sb, options); + svg.Render(sr.RenderItems); + return sb.ToString(); + } } } diff --git a/src/EPPlus/Drawing/ExcelShapeBase.cs b/src/EPPlus/Drawing/ExcelShapeBase.cs index 3d6b31b552..1fcc9c7091 100644 --- a/src/EPPlus/Drawing/ExcelShapeBase.cs +++ b/src/EPPlus/Drawing/ExcelShapeBase.cs @@ -11,9 +11,12 @@ Date Author Change 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ using OfficeOpenXml.Core; +using OfficeOpenXml.Drawing.Chart.Style; using OfficeOpenXml.Drawing.Shape; +using OfficeOpenXml.Drawing.Style.Coloring; using OfficeOpenXml.Drawing.Style.Effect; using OfficeOpenXml.Drawing.Style.ThreeD; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.Style; using System; using System.Collections.Generic; @@ -48,7 +51,7 @@ public class ExcelShapeBase : ExcelDrawing private string _fontPath = "{0}{1}:txBody/a:p/a:pPr/a:defRPr"; private string _textBodyPath = "{0}{1}:txBody/a:bodyPr"; private string _presetGeometryPath = "{0}{1}:spPr/a:prstGeom/a:avLst"; - + private string _stylePath = "{0}xdr:style"; private Dictionary _adjustmentPoints = null; internal ExcelShapeBase(ExcelDrawings drawings, XmlNode node, string topPath, string nvPrPath, ExcelGroupShape parent=null, DrawingsCollectionType DrawingsType = DrawingsCollectionType.Worksheet) : @@ -78,6 +81,7 @@ private void Init(string topPath) _fontPath = string.Format(_fontPath, topPath, NamespacePrefixes[_prefixIndex]); _textBodyPath = string.Format(_textBodyPath, topPath, NamespacePrefixes[_prefixIndex]); _presetGeometryPath = string.Format(_presetGeometryPath, topPath, NamespacePrefixes[_prefixIndex]); + _stylePath = string.Format(_stylePath, topPath); AddSchemaNodeOrder(SchemaNodeOrder, new string[] { "nvSpPr", "spPr", "txSp", "style", "txBody", "hlinkClick", "hlinkHover", "xfrm", "custGeom", "prstGeom", "noFill", "solidFill", "blipFill", "gradFill", "pattFill", "grpFill", "ln", "effectLst", "effectDag", "scene3d", "sp3d", "pPr", "r", "br", "fld", "endParaRPr", "lnRef", "fillRef", "effectRef", "fontRef" }); } /// @@ -98,13 +102,17 @@ public virtual eShapeStyle Style get { string v = GetXmlNodeString(_shapeStylePath); + if(string.IsNullOrEmpty(v)) + { + return eShapeStyle.CustomShape; + } try { return (eShapeStyle)Enum.Parse(typeof(eShapeStyle), v, true); } catch { - throw (new Exception(string.Format("Invalid shapetype {0}", v))); + throw (new Exception(string.Format("Invalid shape type {0}", v))); } } set @@ -204,7 +212,7 @@ public ExcelDrawingLineEnd TailEnd return _tailEnd; } } - ExcelTextFont _font = null; + ExcelTextFontXml _font = null; /// /// Font properties /// @@ -212,19 +220,26 @@ public ExcelTextFont Font { get { - if (_font == null) + if(_font == null) { - XmlNode node = TopNode.SelectSingleNode(_paragraphPath, NameSpaceManager); - if (node == null) - { - Text = ""; //Creates the node p element - node = TopNode.SelectSingleNode(_paragraphPath, NameSpaceManager); - } - _font = new ExcelTextFont(_drawings, NameSpaceManager, TopNode, _fontPath, SchemaNodeOrder); + _font = (ExcelTextFontXml)TextBody.Paragraphs.CreateOrGetDefaultRunProperties(_fontPath, TopNode); } return _font; } } + private ExcelChartStyleEntry _themeStyles=null; + internal ExcelChartStyleEntry ThemeStyles + { + get + { + var styleNode = GetNode(_stylePath); + if(styleNode!=null) + { + _themeStyles = new ExcelChartStyleEntry(NameSpaceManager, styleNode, ".", null, "a"); + } + return _themeStyles; + } + } bool isSpInit = false; private void InitSpPr() { @@ -280,7 +295,8 @@ public ExcelParagraphCollection RichText { if (_richText == null) { - _richText = new ExcelParagraphCollection(this, NameSpaceManager, TopNode, _paragraphPath, SchemaNodeOrder); + var txtBody = TextBody; + _richText = new ExcelParagraphCollection(txtBody, this, NameSpaceManager, TopNode, _paragraphPath, SchemaNodeOrder); } return _richText; } @@ -457,7 +473,7 @@ public ExcelTextBody TextBody { if (_textBody == null) { - _textBody = new ExcelTextBody(NameSpaceManager, TopNode, _textBodyPath, this.SchemaNodeOrder); + _textBody = new ExcelTextBody(_drawings, NameSpaceManager, TopNode, _textBodyPath, this.SchemaNodeOrder); } return _textBody; } @@ -479,6 +495,44 @@ public EPPlusReadOnlyList GetAdjustmentPointsNames() strings._list = _adjustmentPoints.Keys.ToList(); return strings; } + public EPPlusReadOnlyList GetAdjustmentPointsList() + { + if(HasCustomAdjustmentPoints()==false) + { + return GetDefaultAdjustmentPointList(); + } + var nodes = GetNodes(_presetGeometryPath + "/a:gd"); + var list = new EPPlusReadOnlyList(); + foreach(XmlElement gdNode in nodes) + { + var fmla = gdNode.GetAttribute("fmla"); + if (string.IsNullOrEmpty(fmla)==false) + { + list.Add(GetValueFromFormula(fmla)); + } + } + return list; + } + public bool HasCustomAdjustmentPoints() + { + return ExistsNode(_presetGeometryPath + "/a:gd"); + } + private EPPlusReadOnlyList GetDefaultAdjustmentPointList() + { + var l = new EPPlusReadOnlyList(); + l._list = ShapeGuidesFactory.GetAdjustmentPointList(Style); + return l; + } + + private int GetValueFromFormula(string fmla) + { + var tokens = fmla.Split([" "],StringSplitOptions.RemoveEmptyEntries); + if (tokens.Length > 1 && tokens[0].Equals("val") && int.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out int result)) + { + return result; + } + return 0; + } /// /// Adjust the named point with value. @@ -500,7 +554,7 @@ public void SetAdjustmentPoint(string name, int value) foreach (KeyValuePair guide in _adjustmentPoints) { //create xml node - var gd = TopNode.SelectSingleNode(_presetGeometryPath + "/a:gd[@name =\"{guide.Key}\"]", NameSpaceManager); + var gd = TopNode.SelectSingleNode(_presetGeometryPath + $"/a:gd[@name =\"{guide.Key}\"]", NameSpaceManager); if (gd == null) { gd = TopNode.OwnerDocument.CreateElement("gd", NameSpaceManager.LookupNamespace("a")); @@ -508,10 +562,11 @@ public void SetAdjustmentPoint(string name, int value) ((XmlElement)gd).SetAttribute("fmla", guide.Value.fmlaValue); var parent = TopNode.SelectSingleNode(_presetGeometryPath, NameSpaceManager); parent.AppendChild(gd); + } else { - gd.Attributes["fmla"].Value = _adjustmentPoints[name].fmlaValue; + gd.Attributes["fmla"].Value = _adjustmentPoints[guide.Key].fmlaValue; } } } @@ -536,12 +591,27 @@ internal override void CellAnchorChanged() if (_fill != null) _fill.SetTopNode(TopNode); if (_border != null) _border.TopNode = TopNode; if (_effect != null) _effect.TopNode = TopNode; - if (_font != null) _font.TopNode = TopNode; + if (_font != null) _font.XmlHelper.TopNode = TopNode; if (_threeD != null) _threeD.TopNode = TopNode; if (_tailEnd != null) _tailEnd.TopNode = TopNode; if (_headEnd != null) _headEnd.TopNode = TopNode; if (_richText != null) _richText.TopNode = TopNode; if (_textBody != null) _textBody.TopNode = TopNode; } + + internal override void SaveDrawing(bool hasLoadedPivotTables) + { + base.SaveDrawing(hasLoadedPivotTables); + if(_textBody != null) + { + _textBody.SaveTextBody(); + } + //if(_richText != null) + //{ + // //We set the end run after the user has set all properties for all given runs + // //This ensures we need not update the node repeatedly. + // RichText.UpdateXmlEndParagraphRunProperties(); + //} + } } } diff --git a/src/EPPlus/Drawing/ImageHandling/GenericImageHandler.cs b/src/EPPlus/Drawing/ImageHandling/GenericImageHandler.cs index a455395638..9f04ef981d 100644 --- a/src/EPPlus/Drawing/ImageHandling/GenericImageHandler.cs +++ b/src/EPPlus/Drawing/ImageHandling/GenericImageHandler.cs @@ -29,7 +29,7 @@ public HashSet SupportedTypes /// Retrieves the image bounds and resolution for an image /// /// The image data - /// Type type of image + /// BulletType type of image /// The width of the image /// The height of the image /// The horizontal resolution in DPI diff --git a/src/EPPlus/Drawing/ImageHandling/PictureStore.cs b/src/EPPlus/Drawing/ImageHandling/PictureStore.cs index 71f66a9039..9d1c881afb 100644 --- a/src/EPPlus/Drawing/ImageHandling/PictureStore.cs +++ b/src/EPPlus/Drawing/ImageHandling/PictureStore.cs @@ -20,6 +20,7 @@ Date Author Change using OfficeOpenXml.Packaging; using System.Linq; using OfficeOpenXml.Utils.FileUtils; +using OfficeOpenXml.Drawing.Vml; namespace OfficeOpenXml.Drawing { internal class ImageInfo @@ -540,7 +541,7 @@ internal static string SavePicture(byte[] image, IPictureContainer container, eP container.ImageHash = ii.Hash; } - //Set the Image and save it to the package. + //Set the BulletImage and save it to the package. container.RelPic = container.RelationDocument.RelatedPart.CreateRelationship(UriHelper.GetRelativeUri(container.RelationDocument.RelatedUri, container.UriPic), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/image"); //AddNewPicture(img, picRelation.Id); @@ -553,5 +554,26 @@ public void Dispose() { _images = null; } + + internal static void RemoveImage(IPictureContainer container) + { + var relDoc = container.RelationDocument; + if (relDoc.Hashes.TryGetValue(container.ImageHash, out HashInfo hi)) + { + if (hi.RefCount <= 1) + { + relDoc.Package.PictureStore.RemoveImage(container.ImageHash, container); + if (container.RelPic != null) + { + relDoc.RelatedPart.DeleteRelationship(container.RelPic.Id); + } + relDoc.Hashes.Remove(container.ImageHash); + } + else + { + hi.RefCount--; + } + } + } } } diff --git a/src/EPPlus/Drawing/OleObject/ExcelOleObject.cs b/src/EPPlus/Drawing/OleObject/ExcelOleObject.cs index a147615de7..acc0348ee7 100644 --- a/src/EPPlus/Drawing/OleObject/ExcelOleObject.cs +++ b/src/EPPlus/Drawing/OleObject/ExcelOleObject.cs @@ -337,7 +337,7 @@ internal void CreateOleObject(ExcelDrawings drawings, XmlNode node, string name, } emf.SetNewTextInDefaultEMFImage(Path.GetFileName(parameters.OlePath)); image = emf.GetBytes(); - //Add image to Picture Store + //Add image to Blip Store _mediaImage = _worksheet._package.PictureStore.AddImage(image, null, ePictureType.Emf); } diff --git a/src/EPPlus/Drawing/OleObject/Structures/OleObjectDataStructures.cs b/src/EPPlus/Drawing/OleObject/Structures/OleObjectDataStructures.cs index bf57ddad74..f84d9fc5b3 100644 --- a/src/EPPlus/Drawing/OleObject/Structures/OleObjectDataStructures.cs +++ b/src/EPPlus/Drawing/OleObject/Structures/OleObjectDataStructures.cs @@ -43,7 +43,7 @@ internal class MonikerStream internal CLSID ClsId; internal UInt32 StreamData1 = 2; internal UInt16 StreamData2 = 33; - internal UInt32 StreamData3 = 0; //Size of StreamData4 + internal UInt32 StreamData3 = 0; //FontSize of StreamData4 internal string StreamData4 = ""; internal Encoding Encoding = Encoding.Unicode; } diff --git a/src/EPPlus/Drawing/RectBase.cs b/src/EPPlus/Drawing/RectBase.cs new file mode 100644 index 0000000000..23eb81e64e --- /dev/null +++ b/src/EPPlus/Drawing/RectBase.cs @@ -0,0 +1,53 @@ +namespace OfficeOpenXml.Drawing +{ + internal class RectBase + { + internal double Left { get; set; } + internal double Top { get; set; } + internal double Right { get; set; } + internal double Bottom { get; set; } + + internal RectBase() + { + } + + internal RectBase(double width, double height) + { + Left = 0; + Top = 0; + Right = width; + Bottom = height; + } + internal RectBase(double left, double top, double right, double bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + internal double Width + { + get + { + return Right - Left; + } + set + { + Right = Left + value; + } + } + + internal double Height + { + get + { + return Bottom - Top; + } + set + { + Bottom = Top + value; + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisOptions.cs b/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisOptions.cs new file mode 100644 index 0000000000..bd11246ae5 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisOptions.cs @@ -0,0 +1,17 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing.Chart; +using System.Drawing; + +internal class AxisOptions +{ + public double? LockedMin { get; set; } + public double? LockedMax { get; set; } + public double? LockedInterval { get; set; } + public eTimeUnit? LockedIntervalUnit { get; set; } + public bool AddPadding { get; set; } = false; + public ExcelChartAxisStandard Axis { get; set; } + public bool IsStacked100 { get; set; } + public RenderItem ChartSize { get; set; } + public string NumberFormat { get; set; } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisScale.cs b/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisScale.cs new file mode 100644 index 0000000000..1b2515ff79 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/Axis/AxisScale.cs @@ -0,0 +1,17 @@ +using EPPlus.Export.ImageRenderer; +using EPPlus.Export.Renderer; +using OfficeOpenXml.Drawing.Chart; +using System.Collections.Generic; + +internal class AxisScale +{ + public double Min { get; set; } + public double Max { get; set; } + public double MajorInterval { get; set; } + public double MinorInterval { get; set; } + public int TickCount { get; set; } + public eTimeUnit? MajorDateUnit { get; set; } + public eTimeUnit? MinorDateUnit { get; set; } + public eTextOrientation TextOrientation { get; set; } + public List DisplayValues { get; set; } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/Axis/CategoryAxisScaleCalculator.cs b/src/EPPlus/Drawing/Renderer/Chart/Axis/CategoryAxisScaleCalculator.cs new file mode 100644 index 0000000000..bed313ba57 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/Axis/CategoryAxisScaleCalculator.cs @@ -0,0 +1,188 @@ +using EPPlus.Export.Renderer; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml; +using OfficeOpenXml.DataValidation; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Information; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Utils.DateUtils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart.Util +{ + internal class CategoryAxisScaleCalculator + { + + internal static AxisScale CalculateHorizontalAxisByWidth(ref List values, ITextMeasurer tm, AxisOptions options) + { + var ax = options.Axis; + var plotAreaWidth = options.ChartSize.Bounds.Width; + var mf = ax.Font.GetMeasureFont(); + List displayValues = GetUniqueValues(values).Select(x=>(object)x.ToString()).ToList(); + var uniqeItems = displayValues.Count; + + var res = tm.MeasureText(displayValues[0].ToString(), mf); + + //Get interval for maximum width with vertical text. + var interval = GetMinUnitVerticalText(displayValues.Count, res.Height, plotAreaWidth); + + + //Get max text width when using diagonal text + var width = mf.Size * Math.Sqrt(2); + var margin = mf.Size * 0.5; + + if (FitAsVerticalDiagonalText(displayValues.Count, interval, width, margin, plotAreaWidth)) //Check diagonal + { + if(FitAsHorizontalText(displayValues, interval, mf, tm, plotAreaWidth)) //Check horizontal + { + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + Min = 1, + Max = displayValues.Count, + TextOrientation = eTextOrientation.Horizontal, + DisplayValues = displayValues + }; + } + else + { + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + Min = 1, + Max = displayValues.Count, + TextOrientation = eTextOrientation.Diagonal, + DisplayValues = displayValues + }; + } + } + if(interval != 1) + { + var removeCount = interval - 1; + var c = (int)Math.Truncate(values.Count / (double)interval); + for(int i=0;i<=c;i++) + { + for(int j=0;j values, ITextMeasurer tm, AxisOptions options) + { + var ax = options.Axis; + var plotAreaHeight = options.ChartSize.Bounds.Height; + var mf = ax.Font.GetMeasureFont(); + List displayValues = GetUniqueValues(values).Select(x => (object)x.ToString()).ToList(); + var uniqeItems = displayValues.Count; + var res = tm.MeasureText(displayValues[0].ToString(), mf); + int interval = 1; + while (FitAsVerticalDiagonalText(displayValues.Count, interval, res.Height, 1.2D, plotAreaHeight)==false) //Check horizontal + { + interval++; + } + if (interval != 1) + { + var removeCount = interval-1; + var c = (int)Math.Truncate(displayValues.Count / (double)interval); + for (int i = 0; i <= c; i++) + { + for (int j = 0; j < removeCount; j++) + { + if (i + 1 < displayValues.Count) + { + displayValues.RemoveAt(i + 1); + } + } + } + } + + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + Min = 1, + Max = uniqeItems, + TextOrientation = eTextOrientation.Horizontal, + DisplayValues = displayValues + }; + } + internal static List GetUniqueValues(List values) + { + var ret = new List(); + var hs = new HashSet(); + foreach(var v in values) + { + if(v is string[]) + { + var s = (string[])v; + var key = s[0] + s[1]; + if(hs.Add(key)) + { + ret.Add(s[0]); + } + } + else + { + ret.Add(v); + } + } + return ret; + } + + private static bool FitAsHorizontalText(List displayValues, int interval, MeasurementFont mf, ITextMeasurer tm, double plotAreaWidth) + { + var margin = mf.Size * 0.3; + var width = tm.MeasureText(displayValues[0].ToString(), mf).Width + margin; + var pos = interval; + while (pos < displayValues.Count && width < plotAreaWidth) + { + width = tm.MeasureText(displayValues[pos].ToString(), mf).Width + margin; + if(width > plotAreaWidth) return false; + pos += interval; + } + return width <= plotAreaWidth; + } + + private static bool FitAsVerticalDiagonalText(int itemCount, int interval, double textWidth, double margin, double plotAreaWidthHeight) + { + var items = Math.Truncate(itemCount * 1D / interval); + return items * textWidth + (items - 1) * margin < plotAreaWidthHeight; + } + + private static int GetMinUnitVerticalText(int itemCount, double textHeight, double plotAreaWidth) + { + var interval = 1; + var margin = 0D; + var items = Math.Truncate((double)itemCount / interval); + while (items * textHeight + (items - 1) * margin >= plotAreaWidth) + { + interval++; + items = Math.Truncate((double)itemCount / interval); + } + + return interval; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/Axis/DateAxisScaleCalculator.cs b/src/EPPlus/Drawing/Renderer/Chart/Axis/DateAxisScaleCalculator.cs new file mode 100644 index 0000000000..41568ac8f8 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/Axis/DateAxisScaleCalculator.cs @@ -0,0 +1,560 @@ +using EPPlus.Export.Renderer; +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Information; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Utils.DateUtils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart.Util +{ + internal class DateAxisScaleCalculator + { + /// + /// Calculate automatic axis settings for date data + /// + internal static AxisScale Calculate(double dataMin, double dataMax, AxisOptions axisOptions = null) + { + + ComputeAutoAxis(DateTime.FromOADate(dataMin), DateTime.FromOADate(dataMax), axisOptions.AddPadding); + var range = dataMax - dataMin; + + // Calculate major majorUnit based on range + CalculateMajorUnit(axisOptions.LockedMin ?? dataMin, axisOptions.LockedMax ?? dataMax, axisOptions.AddPadding, out double majorValue, out double axisMin, out double axisMax, out double minorUnit, out eTimeUnit majorUnit); + if(axisOptions.LockedInterval.HasValue) + { + majorValue = axisOptions.LockedInterval.Value; + } + + return new AxisScale + { + Min = axisMin, + Max = axisMax, + MajorInterval = majorValue, + MajorDateUnit = majorUnit, + MinorDateUnit = majorUnit + }; + } + // Excel's date serial epoch: Dec 30, 1899 + private static readonly DateTime ExcelEpoch = new DateTime(1899, 12, 30); + + // Excel legacy leap year bug: dates after Feb 28, 1900 are offset by 1 + private static readonly DateTime ExcelLeapBugThreshold = new DateTime(1900, 3, 1); + + // Excel's "nice" interval ladder in days + private static readonly int[] NiceIntervals = { 1, 2, 5, 7, 14, 30, 91, 182, 365, 730 }; + private const int TargetTicks = 11; // Excel typically targets 10–12 ticks + public class AxisResult + { + public DateTime AxisMin { get; set; } + public DateTime AxisMax { get; set; } + public int IntervalDays { get; set; } + public double AxisMinSerial { get; set; } + public double AxisMaxSerial { get; set; } + public int TickCount => (int)Math.Round((AxisMaxSerial - AxisMinSerial) / IntervalDays) + 1; + + public override string ToString() => + $"Axis Min : {AxisMin:yyyy-MM-dd} (serial {AxisMinSerial})\n" + + $"Axis Max : {AxisMax:yyyy-MM-dd} (serial {AxisMaxSerial})\n" + + $"Interval : {IntervalDays} day(s)\n" + + $"Ticks : {TickCount}"; + } + /// + /// Converts a DateTime to an Excel serial number (days since Dec 30, 1899), + /// accounting for Excel's 1900 leap year bug. + /// + public static double ToExcelSerial(DateTime date) + { + double serial = (date - ExcelEpoch).TotalDays; + if (date >= ExcelLeapBugThreshold) + serial += 1; // Excel's legacy off-by-one + return serial; + } + + /// + /// Converts an Excel serial number back to a DateTime. + /// + public static DateTime FromExcelSerial(double serial) + { + if (serial >= 61) // 61 = the phantom Feb 29, 1900 in Excel + serial -= 1; + return ExcelEpoch.AddDays(serial); + } + /// + /// Computes Excel-compatible auto axis min, max, and major unit for a date axis. + /// If the OOXML already contains explicit min/max values, use those directly instead. + /// + public static AxisResult ComputeAutoAxis(DateTime dataMin, DateTime dataMax, bool snapInterval) + { + double serialMin = ToExcelSerial(dataMin); + double serialMax = ToExcelSerial(dataMax); + + // Step 1: pick a nice major unit + double rawInterval = (serialMax - serialMin) / 10.0; + int interval = NiceIntervals.FirstOrDefault(v => v >= rawInterval); + if (interval == 0) + interval = 730; // fallback for very large ranges + + double axisMin = serialMin; + double axisMax = serialMax; + if (snapInterval) + { + // Step 2: snap outward to multiples of the interval + axisMin = Math.Floor(serialMin / interval) * interval; + axisMax = Math.Ceiling(serialMax / interval) * interval; + } + else + { + axisMin = serialMin; + axisMax = serialMax; + } + // Step 3: expand until we have enough ticks, then re-snap + while ((axisMax - axisMin) / interval < TargetTicks - 1) + { + axisMin -= interval; + axisMax += interval; + } + + axisMin = Math.Floor(axisMin / interval) * interval; + axisMax = Math.Ceiling(axisMax / interval) * interval; + + return new AxisResult + { + AxisMin = FromExcelSerial(axisMin), + AxisMax = FromExcelSerial(axisMax), + IntervalDays = interval, + AxisMinSerial = axisMin, + AxisMaxSerial = axisMax, + }; + } + /// + /// Calculate major majorUnit based on data range (in days) + /// + private static void CalculateMajorUnit(double min, double max, bool snapToInterval, out double majorValue, out double axisMin, out double axisMax, out double minorUnits, out eTimeUnit majorUnit) + { + var dtMin = DateTime.FromOADate(ExcelNormalizeOADate(min)); + var dtMax = DateTime.FromOADate(ExcelNormalizeOADate(max)); + + var rangeDays = (dtMax - dtMin).TotalDays; + // Target approximately 10 intervals + const int targetIntervals = 9; + var roughUnit = rangeDays / targetIntervals; + double interval; + // Return nice round numbers based on the rough majorUnit + if (roughUnit < 1) + { + interval = majorValue = 1; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 2) + { + interval = majorValue = 2; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 5) + { + // Multiple days - round to nearest day + interval = majorValue = 5; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 7) + { + // Multiple days - round to nearest day + interval = majorValue = 7; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 14) + { + interval = majorValue = 14; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 21) + { + interval = majorValue = 21; + majorUnit = eTimeUnit.Days; + } + else if (roughUnit < 60) + { + majorValue = 1; + interval = 30; + majorUnit = eTimeUnit.Months; + } + else if (roughUnit < 120) + { + majorValue = 2; + interval = 60; + majorUnit = eTimeUnit.Months; + } + else if (roughUnit < 180) + { + majorValue = 3; + interval = 90; + majorUnit = eTimeUnit.Months; + } + else if (roughUnit < 365) + { + majorValue = 6; + interval = 180; + majorUnit = eTimeUnit.Months; + } + else if (roughUnit < 730) + { + majorValue = 1; + interval = 365; + majorUnit = eTimeUnit.Years; + } + else if (roughUnit < 1825) + { + // Multiple years + majorValue = Math.Ceiling(roughUnit / 365); + interval = 365 * majorValue; + majorUnit = eTimeUnit.Years; + } + else + { + // 5-year increments for very long ranges + majorValue = Math.Ceiling(roughUnit / 365 / 5) * 5; + interval = 365 * majorValue; + majorUnit = eTimeUnit.Years; + } + + if (snapToInterval) + { + axisMin = Math.Floor(min / interval) * interval; + axisMax = Math.Ceiling(max / interval) * interval; + + if (axisMax == max) + { + axisMax += interval; + } + // Step 3: expand until we have enough ticks, then re-snap + while ((axisMax - axisMin) / interval < TargetTicks - 1 && ((min - axisMin) < interval * 2)) + { + axisMin -= majorValue; + } + } + else + { + axisMin= min; + axisMax = max; + } + + minorUnits = 1; + } + + private static double ExcelNormalizeOADate(double value) + { + return Math.Min(Math.Max(value, 0), 2958465.99999999); + } + + private static DateTime FloorToUnit(double value, eTimeUnit unit, int interval) + { + var date = DateTime.FromOADate(value); + switch (unit) + { + case eTimeUnit.Days: + if(interval % 7 != 0) + { + return date.Date.AddDays(-(((int)date.DayOfWeek + 6) % 7)); + } + else + { + return date; + } + //return date.Date.AddDays(-(date.DayOfYear % interval)); + case eTimeUnit.Months: + return new DateTime(date.Year, date.Month, 1) + .AddMonths(-((date.Month - 1) % interval)); + + case eTimeUnit.Years: + return new DateTime(date.Year - (date.Year % interval), 1, 1); + default: + return date; + }; + } + + private static DateTime CeilingToUnit(double value, eTimeUnit unit, int interval) + { + DateTime floor = FloorToUnit(value, unit, interval); + + var date = DateTime.FromOADate(value); + if (floor == date) return date; // already on boundary + + switch (unit) + { + case eTimeUnit.Days: + return floor.AddDays(interval); + case eTimeUnit.Months: + return floor.AddMonths(interval); + case eTimeUnit.Years: + return floor.AddYears(interval); + default: + return date; + }; + } + + internal static AxisScale CalculateByWidthAllowDiagonal(double min, double max, ITextMeasurer tm, AxisOptions options) + { + var ax = options.Axis; + var plotAreaWidth = options.ChartSize.Bounds.Width; + var mf = ax.Font.GetMeasureFont(); + int interval; + eTimeUnit unit; + var minString = DateTime.FromOADate(min).ToString(options.NumberFormat); + var res = tm.MeasureText(minString, mf); + if (options.LockedInterval.HasValue) + { + interval = (int)options.LockedInterval.Value; + unit = options.LockedIntervalUnit ?? eTimeUnit.Days; + } + else + { + interval = 1; + unit = eTimeUnit.Days; + //Get interval for maximum width with vertical text. + while (FitAsVerticalDiagonalText(min, max, interval, unit, res.Height, res.Height * 0.3, plotAreaWidth) == false) + { + AddIntervall(ref interval, ref unit); + } + //Get max text width when using diagonal text + var width = mf.Size * Math.Sqrt(2); + var margin = mf.Size * 0.5; + + if (FitAsVerticalDiagonalText(min, max, interval, unit, width, margin, plotAreaWidth)) //Check diagonal + { + if (FitAsHorizontalText(tm, options, min, max, interval, unit, res.Height, plotAreaWidth)) //Check horizontal + { + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + MinorDateUnit = unit, + MajorDateUnit = unit, + Min = min, + Max = max, + TextOrientation = eTextOrientation.Horizontal, + }; + } + else + { + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + MinorDateUnit = unit, + MajorDateUnit = unit, + Min = min, + Max = max, + TextOrientation = eTextOrientation.Diagonal, + }; + } + } + + } + + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + MinorDateUnit = unit, + MajorDateUnit = unit, + Min = min, + Max = max, + TextOrientation = ax.TextBody.VerticalText==OfficeOpenXml.Drawing.eTextVerticalType.Horizontal ? eTextOrientation.Horizontal : eTextOrientation.Vertical, + }; + } + + //private static bool FitAsDiagonalText(double min, double max, int interval, eTimeUnit unit, float size, double plotAreaWidth) + //{ + // var margin = size * 0.5; + // var width = size * Math.Sqrt(2) + margin; + + // if (unit == eTimeUnit.Days) + // { + // return ((max - min) / interval) * width < plotAreaWidth; + // } + // else if(unit == eTimeUnit.Months) + // { + // w + // } + //} + + private static void AddIntervall(ref int interval, ref eTimeUnit unit) + { + if (unit == eTimeUnit.Days) + { + switch (interval) + { + case 1: + interval = 2; + break; + case 2: + interval = 7; //Week + break; + case 7: + interval = 1; //Month + unit = eTimeUnit.Months; + break; + default: + interval *= 10; + break; + } + } + else if (unit == eTimeUnit.Months) + { + unit = eTimeUnit.Years; + } + else if (unit == eTimeUnit.Years) + { + interval++; + } + } + + private static bool FitAsHorizontalText(ITextMeasurer tm, AxisOptions options, double min, double max, int interval, eTimeUnit unit, float height, double width) + { + var minMargin = 2; //2 Points + var minDate = DateTime.FromOADate(min); + var maxDate = DateTime.FromOADate(max); + var date = minDate; + var horizontalWidth = 0D; + var nf = options.NumberFormat; + var mf = options.Axis.Font.GetMeasureFont(); + var angMult = Math.Sin(MathHelper.Radians(45)); + while (date < maxDate) + { + var textWidth = tm.MeasureText(date.ToString(), mf).Width; + horizontalWidth += textWidth + minMargin; + if(horizontalWidth > width) + { + return false; + } + if (unit == eTimeUnit.Days) + { + date = date.AddDays(interval); + } + else if(unit == eTimeUnit.Months) + { + date = minDate.AddDays(1).AddMonths(interval).AddDays(-1); //Extra adds to keep last day of month + } + else + { + date = minDate.AddDays(1); + } + } + return true; + } + + private static bool FitAsVerticalDiagonalText(double min, double max, int interval,eTimeUnit unit, double textWidth, double margin, double plotAreaWidth) + { + if (unit == eTimeUnit.Days) + { + var items = ((max - min) / interval); + return items * textWidth + (items-1) * margin < plotAreaWidth; + } + else if(unit== eTimeUnit.Months) + { + var minDate = DateTime.FromOADate(min); + var maxDate = DateTime.FromOADate(max); + var date = minDate.AddDays(1).AddMonths(interval).AddDays(-1); //Handles last day of month. + var items = 1; + while(date <= maxDate) + { + items++; + if (items * textWidth + (items - 1) * margin > plotAreaWidth) return false; + date = date.AddDays(1).AddMonths(interval).AddDays(-1); + } + return items * textWidth + (items - 1) * margin < plotAreaWidth; + } + else + { + var minDate = DateTime.FromOADate(min); + var maxDate = DateTime.FromOADate(max); + var date = minDate.AddDays(1).AddYears(interval).AddDays(-1); //Handles leap year + var items = 1; + while (date <= maxDate) + { + items++; + if (items * textWidth + (items - 1) * margin > plotAreaWidth) return false; + date = date.AddDays(1).AddYears(interval).AddDays(-1); + } + return items * textWidth + (items - 1) * margin < plotAreaWidth; + + } + } + + internal static AxisScale CalculateByWidthHeight(double widthOrHeight, double min, double max, ITextMeasurer tm, AxisOptions options) + { + var ax = options.Axis; + var mf = ax.Font.GetMeasureFont(); + int interval; + eTimeUnit unit; + var minString = DateTime.FromOADate(min).ToString(options.NumberFormat); + var res = tm.MeasureText(minString, mf); + if (options.LockedInterval.HasValue) + { + interval = (int)options.LockedInterval.Value; + unit = options.LockedIntervalUnit ?? eTimeUnit.Days; + } + else + { + interval = 1; + unit = eTimeUnit.Days; + var range = max - min; + + double axis_min, axis_max; + if (options.AddPadding) + { + axis_min = options.LockedMin ?? Math.Floor((min - 0.5 * range) / interval) * interval; + axis_max = options.LockedMax ?? Math.Ceiling((max + 0.2 * range) / interval) * interval; + } + else + { + axis_min = min; + axis_max = max; + } + //Get interval for maximum width with vertical text. + while (FitAsVerticalDiagonalText(axis_min, axis_max, interval, unit, res.Height, res.Height * 0.3, widthOrHeight) == false) + { + AddIntervall(ref interval, ref unit); + double days; + switch (unit) + { + case eTimeUnit.Months: + days = 30 * interval; + break; + case eTimeUnit.Years: + days = 365 * interval; + break; + default: + days = interval; + break; + } + + if (options.AddPadding) + { + axis_min = options.LockedMin ?? Math.Floor((min - 0.5 * range) / days) * days; + axis_max = options.LockedMax ?? Math.Ceiling((max + 0.2 * range) / days) * days; + } + } + min = axis_min; + max = axis_max; + } + + return new AxisScale() + { + MajorInterval = interval, + MinorInterval = 1, + MinorDateUnit = unit, + MajorDateUnit = unit, + Min = min, + Max = max, + TextOrientation = eTextOrientation.Horizontal + }; + + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/Axis/ValueAxisScaleCalculator.cs b/src/EPPlus/Drawing/Renderer/Chart/Axis/ValueAxisScaleCalculator.cs new file mode 100644 index 0000000000..5c7c68233a --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/Axis/ValueAxisScaleCalculator.cs @@ -0,0 +1,241 @@ +using Microsoft.VisualBasic; +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections.Generic; + +internal class ValueAxisScaleCalculator +{ + internal static AxisScale Calculate(double dataMin, double dataMax, double chartHeightPixels, AxisOptions axisOptions = null) + { + return GetNumberScale(ref dataMin, ref dataMax, chartHeightPixels, ref axisOptions); + } + + private static AxisScale GetNumberScale(ref double dataMin, ref double dataMax, double chartHeightPixels, ref AxisOptions axisOptions) + { + var desiredTicks = chartHeightPixels < 200 ? 4 : + chartHeightPixels < 400 ? 5 : 6; + + if (axisOptions == null) + { + axisOptions = new AxisOptions(); + } + + // Handle equal data series. + if (dataMin == dataMax) + { + if (dataMin < 0) + { + dataMax = 0; + } + else + { + dataMin = 0; + } + } + + var isAllPositive = dataMin >= 0 && dataMax >= 0; + var isAllNegative = dataMin <= 0 && dataMax <= 0; + if(dataMin < 0 && dataMax > 0 && axisOptions.IsStacked100) + { + desiredTicks *= 2; + } + double interval; + if (axisOptions.LockedInterval.HasValue) + { + interval = axisOptions.LockedInterval.Value; + + // Calculate min and max based on locked interval + if (!axisOptions.LockedMin.HasValue) + { + if (axisOptions.AddPadding) + { + dataMin = Math.Floor(dataMin * 0.1 / interval) * interval; + if(axisOptions.IsStacked100 && dataMin < -1) + { + dataMin = -1; + } + if (isAllPositive && dataMin < 0) + { + dataMin = 0; + } + } + } + else + { + dataMin = axisOptions.LockedMin.Value; + } + + if (!axisOptions.LockedMax.HasValue) + { + dataMax = Math.Ceiling(dataMax * 0.1 / interval) * interval; + if (axisOptions.IsStacked100 && dataMin > 1) + { + dataMax = 1; + } + } + else + { + if (axisOptions.AddPadding) + { + dataMax = axisOptions.LockedMax.Value; + if (isAllNegative && dataMax > 0) + { + dataMax = 0; + } + } + } + + int tickCount = (int)Math.Round((dataMax - dataMin) / Math.Min(desiredTicks, interval)) + 1; + return new AxisScale + { + Min = dataMin, + Max = dataMax, + MajorInterval = interval, + TickCount = tickCount + }; + } + else + { + if (axisOptions.LockedMin.HasValue) + { + dataMin = axisOptions.LockedMin.Value; + } + if (axisOptions.LockedMax.HasValue) + { + dataMax = axisOptions.LockedMax.Value; + } + var dataDiff = dataMax - dataMin; + if (axisOptions.LockedMin.HasValue==false && isAllPositive && dataDiff > 0 && dataMin / dataDiff < 5) + { + dataMin = 0; + } + + double dataRange = dataMax - dataMin; + + double axisMin; + double axisMax; + double roughInterval; + double scaleInterval; + + if (axisOptions.AddPadding) + { + // Add padding (10%) + if (axisOptions.LockedMin.HasValue) + { + axisMin = axisOptions.LockedMin.Value; + } + else + { + axisMin = dataMin - (dataRange * 0.05); + if (axisOptions.IsStacked100) + { + if (axisMin < -1) + { + axisMin = -1; + } + else if(axisMin>0) + { + axisMin = 0; + } + } + //Normalize to zero if all data is positive or negative + if (axisMin < 0 && isAllPositive) + { + axisMin = 0; + } + } + + if (axisOptions.LockedMax.HasValue) + { + axisMax = axisOptions.LockedMax.Value; + } + else + { + axisMax = dataMax + (dataRange * 0.05); + if (axisOptions.IsStacked100 && axisMax > 1) + { + axisMax = 1; + } + + if (axisMax > 0 && isAllNegative) + { + axisMax = 0; + } + //if (axisOptions.LockedMin.HasValue==false && axisMin > 0 && dataMin / dataMax <= 0.2) + //{ + // axisMin = 0; + //} + } + + // Calculate interval + roughInterval = (axisMax - axisMin) / desiredTicks; + scaleInterval = GetScaleNumber(roughInterval, true); + + if (!axisOptions.LockedMin.HasValue) axisMin = Math.Floor(axisMin / scaleInterval) * scaleInterval; + if (!axisOptions.LockedMax.HasValue) axisMax = Math.Ceiling(axisMax / scaleInterval) * scaleInterval; + } + else + { + roughInterval = (dataMax - dataMin) / desiredTicks; + scaleInterval = GetScaleNumber(roughInterval, true); + if (dataMin / dataMax >= 0.2) + { + axisMin = 0; + } + else + { + axisMin = Math.Floor(dataMin / scaleInterval) * scaleInterval; + } + + // Calculate interval + + axisMax = dataMax; + } + + var tickCount = (int)Math.Round((axisMax - axisMin) / scaleInterval) + 1; + return new AxisScale + { + Min = axisOptions.LockedMin ?? axisMin, + Max = axisOptions.LockedMax ?? axisMax, + MajorInterval = scaleInterval, + MinorInterval = scaleInterval / 5, + TickCount = tickCount, + }; + } + } + + private static double GetScaleNumber(double value, bool round) + { + double exponent = Math.Floor(Math.Log10(value)); + double fraction = value / Math.Pow(10, exponent); + double scaleFraction; + + if (round) + { + if (fraction < 1.5) scaleFraction = 1; + else if (fraction < 3) scaleFraction = 2; + else if (fraction < 7) scaleFraction = 5; + else scaleFraction = 10; + } + else + { + if (fraction <= 1) scaleFraction = 1; + else if (fraction <= 2) scaleFraction = 2; + else if (fraction <= 5) scaleFraction = 5; + else scaleFraction = 10; + } + + return scaleFraction * Math.Pow(10, exponent); + } + + public static List GetTickValues(AxisScale scale) + { + var ticks = new List(); + for (int i = 0; i < scale.TickCount; i++) + { + double tickValue = scale.Min + (i * scale.MajorInterval); + ticks.Add(Math.Round(tickValue, 10)); // Round to avoid floating point errors + } + return ticks; + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs new file mode 100644 index 0000000000..48fd1a1ff1 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs @@ -0,0 +1,1128 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer; +using EPPlus.Export.ImageRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Export.ImageRenderer.Svg.Chart.Util; +using EPPlus.Export.Renderer; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.FormulaParsing.Excel.Functions.DateAndTime; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Utilities; +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Utils.String; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.AccessControl; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartAxisRenderer : ChartDrawingObject, IDrawingChartAxis + { + private const double COS45 = 0.70710678118654757; //Constant for Math.Sin(Math.PI / 4) --45 degrees + internal ChartAxisRenderer(ChartRenderer sc, ExcelChartAxisStandard ax) : base(sc) + { + Axis = ax; + SetMargins(ax.TextBody); + + if (sc.Chart.Series.Count == 0) + { + return; + } + + if(ax.HasTitle) + { + Title = new ChartTitleRenderer(sc, ax.Title, "Axis Title", this); + } + else + { + Title = null; + } + + Values = GetAxisValue(ax, sc.ChartArea.Rectangle, out double? min, out double? max, out double? majorUnit, out eTimeUnit? dateUnit, out eTextOrientation orientation); + AxisValues = GetAxisDisplayValues(ax, Values, min, max, majorUnit); + + Min = min ?? 0D; + Max = max ?? (Values.Count > 0 ? ConvertUtil.GetValueDouble(Values[Values.Count - 1], false, true) : 0D); + MajorUnit = majorUnit ?? 1; + MinorUnit = ax.MinorUnit ?? GetAutoMinUnit(MajorUnit); + MajorDateUnit = dateUnit; + LabelOrientation = orientation; + + if(Rectangle == null) + { + Rectangle = new RectRenderItem(sc.Bounds); + } + + if (ax.Deleted == false) + { + if (ax.Layout.HasLayout) + { + Rectangle = GetRectFromManualLayout(sc, ax.Layout); + } + else + { + var aav = ax.ActualAxisPosition; + if (ax.IsVertical) + { + if (aav == eActualAxisPosition.Left || + aav == eActualAxisPosition.LeftSecond) + { + Rectangle.Width = GetTextWidest(ax) + LeftMargin; + } + else + { + Rectangle.Width = GetTextWidest(ax) + RightMargin; + } + } + else + { + Rectangle.Height = GetTextHeight(ax); + } + } + + Rectangle.FillColor = "none"; + + Line = new LineRenderItem(Rectangle.Bounds); + Line.SetDrawingPropertiesBorder(ChartRenderer.Theme, ax.Border, sc.Chart.StyleManager.Style?.Title.BorderReference.Color, ax.Border.Fill.Style != eFillStyle.NoFill, 1); + if(Line.BorderWidth < 1) + { + Line.BorderWidth = 1; + } + } + } + + private double GetAutoMinUnit(double majorUnit) + { + return majorUnit / 5; + } + + internal ExcelChartAxisStandard Axis { get; } + internal LineRenderItem Line { get; set; } + private List GetAxisDisplayValues(ExcelChartAxisStandard ax, List values, double? min, double? max, double? majorUnit) + { + var displayValues = new List(); + var nf = new ExcelFormatTranslator(ax.Format, 0); + //Excel replaces the format with a default date format if the axis is date based. + if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) + { + if(ax.Format == "m/d/yyyy") + { + var sdFormat = ExcelNumberFormat.GetFromBuildInFromID(14); //14 is standard regional short date. + nf = new ExcelFormatTranslator(sdFormat, 14); + } + } + foreach (var v in CategoryAxisScaleCalculator.GetUniqueValues(values)) + { + var s = ValueToTextHandler.FormatValue(v, false, nf, null, out bool isValidFormat); + displayValues.Add(s); + } + return displayValues; + } + private double GetTextHeight(ExcelChartAxisStandard ax) + { + var tm = ChartRenderer.TextMeasurer; + var highest = 0D; + var mf = ax.Font.GetMeasureFont(); + foreach (var s in AxisValues) + { + var m = tm.MeasureText(s, mf); + switch (LabelOrientation) + { + case eTextOrientation.Horizontal: + if (m.Height > highest) + { + highest = m.Height; + } + break; + case eTextOrientation.Diagonal: + var width = (m.Width) * COS45; + if (width > highest) + { + highest = width; + } + break; + case eTextOrientation.Vertical: + if (m.Width > highest) + { + highest = m.Width; + } + break; + } + } + return highest.PointToPixel(); + } + + private double GetTextWidest(ExcelChartAxisStandard ax) + { + var mf = ax.Font.GetMeasureFont(); + var shaper = RenderContext.FontEngine.GetShaperForFont(mf); + var tm = new OpenTypeFontTextMeasurer(shaper); + + var widest = 0f; + + foreach(var s in AxisValues) + { + var m= tm.MeasureText(s, mf); + if (m.Width > widest) + { + widest = m.Width; + } + } + return widest; + } + + public List Values + { + get; + private set; + } + public List AxisValues { get; private set; } + + public List MajorTickMarkPositions { get; private set; } + public List MinorTickMarkPositions { get; private set; } + public List MajorGridlinePositions { get; private set; } + public List MinorGridlinePositions { get; private set; } + public ChartAxisTextBoxes Textboxes{get; private set;} + public ChartTitleRenderer Title { get; set; } + public double Min { get; set; } + public double Max { get; set; } + public double MajorUnit { get; set; } + public double MinorUnit { get; set; } + public eTimeUnit? MajorDateUnit { get; set; } + public eTextOrientation LabelOrientation { get; set; } + public bool IsDateScale + { + get; + private set; + } = false; + + public override void AppendRenderItems(List renderItems) + { + Title?.AppendRenderItems(renderItems); + //Title?.Render(sb); + if(Rectangle!=null || Rectangle.Width==0 || Rectangle.Height==0) renderItems.Add(Rectangle); + + var plotareaGroup = ChartRenderer.Plotarea.Group; + if (MajorGridlinePositions != null) + { + foreach (var tm in MajorGridlinePositions) + { + plotareaGroup.RenderItems.Add(tm); + } + } + if (MinorGridlinePositions != null) + { + foreach (var tm in MinorGridlinePositions) + { + plotareaGroup.RenderItems.Add(tm); + } + } + + if (Line != null) renderItems.Add(Line); + + if (MajorTickMarkPositions != null) + { + foreach (var tm in MajorTickMarkPositions) + { + renderItems.Add(tm); + } + } + if (MinorTickMarkPositions != null) + { + foreach (var tm in MinorTickMarkPositions) + { + renderItems.Add(tm); + } + } + + //The axis text boxes is rendered later as they have a higher Z-order. + } + + + internal void AddTickmarksAndValues(List DefItems) + { + if (Axis.Deleted == true) return; + if (Axis.MajorTickMark != eAxisTickMark.None) + { + MajorTickMarkPositions = AddTickmarks(MajorUnit, MajorDateUnit, double.NaN, 4D.PixelToPoint(), Axis.MajorTickMark); + } + + if (Axis.MinorTickMark != eAxisTickMark.None) + { + MinorTickMarkPositions = AddTickmarks(MinorUnit, MajorDateUnit, MajorUnit, 2D.PixelToPoint(), Axis.MinorTickMark); + } + + if(Axis.HasMajorGridlines) + { + MajorGridlinePositions = AddGridlines(MajorUnit, double.NaN, Axis.MajorGridlines, Chart.StyleManager.Style?.GridlineMajor); + } + + if ((Axis.HasMinorGridlines)) + { + MinorGridlinePositions = AddGridlines(MinorUnit, MajorUnit, Axis.MinorGridlines, Chart.StyleManager.Style.GridlineMinor); + } + + if (AxisValues != null && AxisValues.Count > 0 && Axis.Deleted==false && Axis.LabelPosition != eTickLabelPosition.None) + { + Textboxes = new ChartAxisTextBoxes(ChartRenderer); + Textboxes.TextBoxes = GetAxisValueTextBoxes(); + } + } + + private List GetAxisValueTextBoxes() + { + var ret = new List(); + if (Axis.LabelPosition == eTickLabelPosition.None) return ret; + + var mf = Axis.Font.GetMeasureFont(); + + var shaper = RenderContext.FontEngine.GetShaperForFont(mf); + var tm = new OpenTypeFontTextMeasurer(shaper); + + var axisStyle = GetAxisStyleEntry(); + double maxWidth, maxHeight; + if(Axis.AxisPosition==eAxisPosition.Left || Axis.AxisPosition == eAxisPosition.Right) + { + maxWidth = ChartRenderer.ChartArea.Rectangle.Width / 3; //TODO: Check this value. + maxHeight = Rectangle.Height / AxisValues.Count; + } + else + { + switch (LabelOrientation) + { + case eTextOrientation.Vertical: + maxWidth = ChartRenderer.ChartArea.Rectangle.Height / 3; + maxHeight = Rectangle.Width / AxisValues.Count; //TODO: Check this value. + break; + case eTextOrientation.Diagonal: + maxWidth = (Rectangle.Width + Rectangle.Height) / COS45; + maxHeight = ChartRenderer.ChartArea.Rectangle.Height / 3; //TODO: Check this value. + break; + default: + maxWidth = Rectangle.Width / AxisValues.Count; + maxHeight = ChartRenderer.ChartArea.Rectangle.Height / 3; //TODO: Check this value. + break; + } + } + double widest=0; + for (var i = 0; i < AxisValues.Count; i++) + { + var v = AxisValues[i]; + var m = tm.MeasureText(v, mf); + var ticMarkX = GetAxisItemLeft(i, m); + var ticMarkY = GetAxisItemTop(i, m); + var width = m.Width; + var height = m.Height; + double x, y; + if(LabelOrientation==eTextOrientation.Horizontal) + { + if (Axis.AxisType == eAxisType.Cat || Axis.AxisType==eAxisType.Date) + { + x = ticMarkX; + y = ticMarkY; + } + else + { + if(Axis.IsVertical) + { + x = ticMarkX; + if (ChartRenderer.Chart.IsTypeBar()) + { + y = ticMarkY; + } + else + { + y = ticMarkY - height / 2; + } + } + else + { + x = ticMarkX - width / 2; + y = ticMarkY; + } + } + } + else + { + var rot = LabelOrientation == eTextOrientation.Diagonal ? -45 : -90; + double cos = Math.Cos(MathHelper.Radians(rot)); + double sin = Math.Sin(MathHelper.Radians(rot)); + + if (LabelOrientation == eTextOrientation.Diagonal) + { + x = ticMarkX - (height / 2) * cos; + if (Axis.ActualAxisPosition == eActualAxisPosition.Bottom || Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + y = ticMarkY + 4 + TopMargin - (height / 2 * cos); + } + else //Top + { + y = ticMarkY - 4 - BottomMargin - (height/2 * cos); + } + } + else + { + x = ticMarkX - (height / 2); + if (Axis.ActualAxisPosition == eActualAxisPosition.Bottom || Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + y = ticMarkY + BottomMargin + 4; + } + else //Top + { + y = ticMarkY - TopMargin - 4; + } + } + } + + var tb = new DrawingTextBox(Chart, Rectangle.Bounds, x, y, width, height, maxWidth, maxHeight); + if (LabelOrientation == eTextOrientation.Diagonal) + { + tb.Rotation = -45; + if(Axis.ActualAxisPosition==eActualAxisPosition.Bottom || Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + tb.TextAnchor = eTextAnchor.End; + } + } + + else if (LabelOrientation == eTextOrientation.Vertical) + { + tb.Rotation = -90; + if (Axis.ActualAxisPosition == eActualAxisPosition.Bottom || Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + tb.TextAnchor = eTextAnchor.End; + } + } + + var p = Axis.TextBody.Paragraphs.FirstOrDefault(); + + if (p.HorizontalAlignment != eTextAlignment.Center && Axis.AxisType!=eAxisType.Val && (Axis.AxisPosition == eAxisPosition.Bottom || Axis.AxisPosition == eAxisPosition.Top)) + { + //Horizontal axises are always center aligned visually + //Should be broken out as input to ImportParagraph instead of changing the base item + p.HorizontalAlignment = eTextAlignment.Center; + } + + tb.ImportParagraph(p, 0, v); + + //tb.TextBody.Paragraphs[0].AddText(v, Axis.Font); + tb.Rectangle.SetDrawingPropertiesFill(ChartRenderer.Theme, Axis.Fill, axisStyle?.FillReference.Color, true); + + if(widest < tb.Width) + { + widest = tb.Width; + } + ret.Add(tb); + } + + if(Axis.IsVertical) + { + //If the axis is vertical, we need to adjust the left position of the textboxes to align them to the right and not have them overlap with the axis line. + if (Axis.AxisPosition == eAxisPosition.Left) + { + foreach (var tb in ret) + { + tb.Left += (widest - tb.Width); + } + } + else + { + foreach (var tb in ret) + { + tb.Left += LeftMargin; + } + } + } + else if(LabelOrientation==eTextOrientation.Horizontal && IsCatAx()) //Only apples when labels are horizontally aligned + { + //Align the axis labels according to the label alignment setting. This is only relevant for horizontal axis, vertical axis are always right aligned. + var lblAlignment = (Axis as ExcelChartAxisStandard)?.LabelAlignment ?? OfficeOpenXml.eAxisLabelAlignment.Center; + var majorWidth = Rectangle.Width / AxisValues.Count; + if (Axis.CrossingAxis == null || Axis.CrossingAxis.CrossBetween == eCrossBetween.MidCat) + { + foreach (var tb in ret) + { + switch (lblAlignment) + { + case OfficeOpenXml.eAxisLabelAlignment.Left: + tb.Left -= (tb.Width + majorWidth) / 2; + break; + case OfficeOpenXml.eAxisLabelAlignment.Center: + tb.Left -= tb.Width / 2; + break; + case OfficeOpenXml.eAxisLabelAlignment.Right: + tb.Left += (tb.Width + majorWidth) / 2; + break; + } + } + } + else + { + foreach (var tb in ret) + { + switch (lblAlignment) + { + case OfficeOpenXml.eAxisLabelAlignment.Left: + break; + case OfficeOpenXml.eAxisLabelAlignment.Center: + tb.Left += majorWidth / 2 - tb.Width / 2; + break; + case OfficeOpenXml.eAxisLabelAlignment.Right: + tb.Left += majorWidth - tb.Width; + break; + } + } + } + } + else if(LabelOrientation == eTextOrientation.Diagonal) + { + if (!(Axis.CrossingAxis == null || Axis.CrossingAxis.CrossBetween == eCrossBetween.MidCat)) + { + var majorWidth = Rectangle.Width / AxisValues.Count; + foreach (var tb in ret) + { + tb.Left += majorWidth / 2; + } + } + } + + return ret; + } + + private bool IsCatAx() + { + return Axis.AxisType == eAxisType.Cat || (Axis.AxisType == eAxisType.Date && IsDateScale==false); + } + + private double GetAxisItemLeft(int i, OfficeOpenXml.Interfaces.Drawing.Text.TextMeasurement m) + { + if (Axis.IsVertical) + { + return Rectangle.Left; + } + else + { + if (IsCatAx()) + { + double majorWidth; + if (Axis.CrossingAxis == null || Axis.CrossingAxis.CrossBetween == eCrossBetween.Between) + { + majorWidth = Rectangle.Width / AxisValues.Count; + } + else + { + majorWidth = Rectangle.Width / (AxisValues.Count - 1); + } + var majorTickStartingPosition = Rectangle.Left + majorWidth * i; + return majorTickStartingPosition; + } + else + { + var min = ConvertUtil.GetValueDouble(Values[0]); + var max = ConvertUtil.GetValueDouble(Values.Last()); + var v = ConvertUtil.GetValueDouble(Values[i]); + var majorWidth = Rectangle.Width * (v - Min) / (Max - Min); + return Rectangle.Left + majorWidth; + } + //} + } + } + + private double GetAxisItemTop(int i, OfficeOpenXml.Interfaces.Drawing.Text.TextMeasurement m) + { + if (Axis.ActualAxisPosition == eActualAxisPosition.Top || Axis.ActualAxisPosition == eActualAxisPosition.TopSecond) + { + switch (LabelOrientation) + { + case eTextOrientation.Vertical: + case eTextOrientation.Diagonal: + return Rectangle.Bottom; + default: + return Rectangle.Bottom - m.Height - TopMargin; + } + } + else if (Axis.ActualAxisPosition == eActualAxisPosition.Bottom || Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + switch(LabelOrientation) + { + case eTextOrientation.Vertical: + if (Axis.LabelPosition == eTickLabelPosition.Low) + { + return Rectangle.Bottom - m.Width; + } + else + { + return Rectangle.Top; + } + case eTextOrientation.Diagonal: + if (Axis.LabelPosition == eTickLabelPosition.Low) + { + return Rectangle.Bottom - (m.Width+m.Height)* COS45; + } + else + { + return Rectangle.Top; + } + default: + if (Axis.LabelPosition == eTickLabelPosition.Low) + { + return Rectangle.Bottom - m.Height; + } + else if (Axis.LabelPosition == eTickLabelPosition.NextTo) + { + return Rectangle.Top + BottomMargin; + } + else //TODO:Add support for hight. + { + return Rectangle.Top + BottomMargin; + } + } + } + else + { + if (Axis.AxisType == eAxisType.Cat || Axis.AxisType == eAxisType.Date) + { + var majorHeight = Rectangle.Height / (AxisValues.Count); + return Rectangle.Top + majorHeight * (AxisValues.Count - i) - ((majorHeight / 2) + m.Height / 2); + } + else + { + var majorHeight = Rectangle.Height / (AxisValues.Count-1); + return Rectangle.Top + majorHeight * (AxisValues.Count - i - 1); + //return Rectangle.Top + majorHeight * (AxisValues.Count - i - 1); + } + } + + } + + private List AddTickmarks(double units, eTimeUnit? dateUnit, double parentUnit, double tickMarkWidth, eAxisTickMark type) + { + var axisStyle = GetAxisStyleEntry(); + + var tms = new List(); + double min, max, addMinor=0D; + if(double.IsNaN(parentUnit)==false && parentUnit==units) + { + addMinor = parentUnit / 2; + } + + if (Axis.AxisType == eAxisType.Cat) + { + min = 1; + if (Axis.CrossingAxis==null || Axis.CrossingAxis.CrossBetween == eCrossBetween.Between) + { + max = AxisValues.Count; + } + else + { + max = AxisValues.Count - 1; + } + } + else + { + min = Min; + max = Max; + } + + double tickMarkWidthInside=0, tickMarkWidthOutside=0; + if(type==eAxisTickMark.In || type==eAxisTickMark.Cross) + { + tickMarkWidthInside = tickMarkWidth; + } + if(type==eAxisTickMark.Out || type == eAxisTickMark.Cross) + { + tickMarkWidthOutside = tickMarkWidth; + } + var diff = max - min + 1; + double d = min + addMinor; + while (d <= max+1) + { + if (double.IsNaN(parentUnit) || (d % parentUnit != 0)) + { + double x1, y1, x2, y2; + switch (Axis.ActualAxisPosition) + { + case eActualAxisPosition.Left: + case eActualAxisPosition.LeftSecond: + y1 = (float)(Rectangle.Top + Rectangle.Height - ((d - min) / diff * Rectangle.Height)); + y2 = y1; + x1 = (float)Rectangle.Right - tickMarkWidthOutside; + x2 = (float)Rectangle.Right + tickMarkWidthInside; + break; + case eActualAxisPosition.Right: + case eActualAxisPosition.RightSecond: + y1 = (float)(Rectangle.Top + Rectangle.Height - ((d - min) / diff * Rectangle.Height)); + y2 = y1; + x1 = (float)Rectangle.Left - tickMarkWidthInside; + x2 = (float)Rectangle.Left + tickMarkWidthOutside; + break; + case eActualAxisPosition.Top: + case eActualAxisPosition.TopSecond: + x1 = (float)(Rectangle.Left + ((d - min) / diff * Rectangle.Width)); + x2 = x1; + y1 = (float)Rectangle.Bottom - tickMarkWidthOutside; + y2 = (float)Rectangle.Bottom + tickMarkWidthInside; + break; + case eActualAxisPosition.Bottom: + case eActualAxisPosition.BottomSecond: + x1 = (float)(Rectangle.Left + ((d - min) / diff * Rectangle.Width)); + x2 = x1; + y1 = (float)Rectangle.Top - tickMarkWidthInside; + y2 = (float)Rectangle.Top + tickMarkWidthOutside; + break; + default: + throw new InvalidOperationException("Invalid axis position"); + } + var tm = new LineRenderItem(ChartRenderer.Bounds); + tm.X1 = x1; + tm.Y1 = y1; + tm.X2 = x2; + tm.Y2 = y2; + tm.SetDrawingPropertiesBorder(ChartRenderer.Theme, Axis.Border, axisStyle?.BorderReference.Color, true); + if(tm.BorderWidth<1) //Excel seems to have this as minimum width for tick marks, so we enforce it here to make sure they are visible. + { + tm.BorderWidth = 1; + } + tms.Add(tm); + } + switch (dateUnit) + { + case eTimeUnit.Years: + d = DateTime.FromOADate(d).AddYears((int)units).ToOADate(); + break; + case eTimeUnit.Months: + if (units>=1D) + { + d = DateTime.FromOADate(d).AddMonths((int)units).ToOADate(); + } + else + { + var dt = DateTime.FromOADate(d); + var days = DateTime.DaysInMonth(dt.Year, dt.Month) * units; + d += days; + } + break; + default: + d += units; + break; + } + } + return tms; + } + private List AddGridlines(double units, double parentUnit, ExcelDrawingBorder lineItem, ExcelChartStyleEntry styleEntry) + { + var axisStyle = GetAxisStyleEntry(); + + var tms = new List(); + double min; + if (Axis.AxisType == eAxisType.Cat) + { + min = 0; + } + else + { + min = Min; + } + var pa = ChartRenderer.Plotarea; + var diff = Max - min; + + List points = new List(); + var group = ChartRenderer.Plotarea.Group; + for (double d = min; d <= Max; d += units) + { + if(d==min && Line!=null && Line.BorderWidth>0) continue; + if (double.IsNaN(parentUnit) || (d % parentUnit != 0)) + { + switch (Axis.AxisPosition) + { + case eAxisPosition.Left: + case eAxisPosition.Right: + points.Add(new Point(0f, (float)(pa.Rectangle.Height - ((d - min) / diff * pa.Rectangle.Height)))); + break; + case eAxisPosition.Top: + case eAxisPosition.Bottom: + var xValue = (float)(((d - min) / diff * pa.Rectangle.Width)); + points.Add(new Point(xValue, 0f)); + break; + default: + throw new InvalidOperationException("Invalid axis position"); + } + } + } + + float x1, y1, x2, y2; + + string id = ""; + + switch (Axis.AxisPosition) + { + case eAxisPosition.Left: + case eAxisPosition.Right: + id = "xGridLine"; + y1 = (float)points.Last().Top; + y2 = y1; + x1 = (float)0; + x2 = (float)pa.Rectangle.Width; + break; + case eAxisPosition.Top: + case eAxisPosition.Bottom: + id = "yGridLine"; + x1 = (float)points[0].Left; + x2 = x1; + y1 = 0; + y2 = (float)pa.Rectangle.Height; + break; + default: + throw new InvalidOperationException("Invalid axis position"); + } + + var tm = new LineRenderItem(ChartRenderer.Bounds); + tm.X1 = x1; + tm.Y1 = y1; + tm.X2 = x2; + tm.Y2 = y2; + tm.SetDrawingPropertiesBorder(ChartRenderer.Theme, lineItem, styleEntry?.BorderReference.Color, true, lineItem.Width); + + tm.DefId = id; + + tms.Add(tm); + + var distX = (float)points.Last().Left - points[0].Left; + var distY = points[0].Top - (float)points.Last().Top; + + var offsetX = distX / (points.Count-1); + var offsetY = distY / (points.Count-1); + + for(int i = 0; i < points.Count; i++) + { + var refItem = new UseReferenceRenderItem(ChartRenderer.Bounds, "#" + id); + if(id == "xGridLine") + { + refItem.X = 0f; + refItem.Y = offsetY*i; + } + else if(id == "yGridLine") + { + refItem.X = offsetX*i; + refItem.Y = 0f; + } + tms.Add(refItem); + } + + + return tms; + } + + private ExcelChartStyleEntry GetAxisStyleEntry() + { + ExcelChartStyleEntry axisStyle; + switch (Axis.AxisType) + { + case eAxisType.Cat: + axisStyle = Chart.StyleManager.Style?.CategoryAxis; + break; + case eAxisType.Serie: + axisStyle = Chart.StyleManager.Style?.SeriesAxis; + break; + default: + axisStyle = Chart.StyleManager.Style?.ValueAxis; + break; + } + + return axisStyle; + } + + internal double GetPositionInPlotarea(double val, bool startValue=false) + { + if (Axis.AxisPosition == eAxisPosition.Left || Axis.AxisPosition == eAxisPosition.Right) + { + if (Axis.AxisType == eAxisType.Cat) + { + var majorHeight = ChartRenderer.Plotarea.Rectangle.Height / Max; + if(startValue) + { + return majorHeight * val; + } + else + { + //if (Axis.CrossingAxis == null || Axis.CrossingAxis.CrossBetween == eCrossBetween.Between) + //{ + // majorHeight = DrawingChart.Plotarea.Rectangle.Height / (Max - 1); + // return majorHeight * val; + //} + //else + //{ + return majorHeight * val + (majorHeight / 2); + //} + } + } + else if (Axis.AxisType == eAxisType.Date && IsDateScale == false) + { + //if (val < Min || val > Max) return double.NaN; + var diff = Max - Min + 1; + return (((val - Min) / diff * ChartRenderer.Plotarea.Rectangle.Height)); + } + else + { + //if (val < Min || val > Max) return double.NaN; + var diff = Max - Min; + return (Max - val) / diff * ChartRenderer.Plotarea.Rectangle.Height; + } + } + else + { + if (Axis.AxisType == eAxisType.Cat) + { + var majorWidth = ChartRenderer.Plotarea.Rectangle.Width / Max; + if (startValue) + { + return majorWidth * val; + } + else + { + if(Axis.CrossingAxis == null || Axis.CrossingAxis.CrossBetween==eCrossBetween.Between) + { + return majorWidth * val + (majorWidth / 2); + } + else + { + majorWidth = ChartRenderer.Plotarea.Rectangle.Width / (Max - 1); + return majorWidth * val; + } + } + } + else if(Axis.AxisType == eAxisType.Date && IsDateScale==false) + { + if (val < Min || val > Max) return double.NaN; + var diff = Max - Min + 1; + return (((val - Min) / diff * ChartRenderer.Plotarea.Rectangle.Width)); + } + else + { + if (val < Min || val > Max) return double.NaN; + var diff = Max - Min; + return (((val - Min) / diff * ChartRenderer.Plotarea.Rectangle.Width)); + } + } + } + protected List GetAxisValue(ExcelChartAxisStandard ax, RenderItem rect, out double? min, out double? max, out double? majorUnit, out eTimeUnit? dateUnit, out eTextOrientation orientation) + { + var values = ax.GetAxisValues(out bool isCount); + var isNumeric = values.Any(x => x == null || x.IsNumeric()); + var options = new AxisOptions + { + LockedMin = ax.MinValue, + LockedMax = ax.MaxValue, + LockedInterval = ax.MajorUnit, + LockedIntervalUnit = ax.MajorTimeUnit, + AddPadding = ShouldHavePadding(), + Axis = ax, + IsStacked100 = Chart.IsTypePercentStacked(), + ChartSize = rect + }; + + if ((ax.AxisType == eAxisType.Cat || (ax.IsDate && isNumeric==false)) && + isCount == false) + { + AxisScale res; + if (ax.IsVertical) + { + res = CategoryAxisScaleCalculator.CalculateVerticalAxisByHeight(ref values, ChartRenderer.TextMeasurer, options); + } + else + { + res = CategoryAxisScaleCalculator.CalculateHorizontalAxisByWidth(ref values, ChartRenderer.TextMeasurer, options); + } + + min = res.Min; + max = res.Max; + majorUnit = res.MajorInterval; + dateUnit = null; + orientation = res.TextOrientation; + + return res.DisplayValues; + } + + var l = new List(); + min = double.MaxValue; + max = double.MinValue; + foreach (var v in values) + { + var d = ConvertUtil.GetValueDouble(v, false, true); + if (double.IsNaN(d)) + { + d = 0; + } + if (min > d) + { + min = d; + } + if (max < d) + { + max = d; + } + } + + var length = ax.AxisPosition == eAxisPosition.Left || ax.AxisPosition == eAxisPosition.Right ? ChartRenderer.Bounds.Height : ChartRenderer.Bounds.Width; //Fix and use plotarea width/height. + if(isCount) + { + majorUnit = 1; + dateUnit = null; + for (int i=1;i<=max;i++) + { + l.Add(i); + } + var res = CategoryAxisScaleCalculator.CalculateHorizontalAxisByWidth(ref l, ChartRenderer.TextMeasurer, options); + + min = res.Min; + max = res.Max; + majorUnit = res.MajorInterval; + dateUnit = null; + orientation = res.TextOrientation; + + return l.ToList(); + } + if(ax.AxisType==eAxisType.Val) + { + AdjustminMaxFromChartObjects(ax, ref min, ref max); + } + if (ax.IsDate) + { + AxisScale res; + if (ax.IsVertical) + { + res = DateAxisScaleCalculator.CalculateByWidthHeight(options.ChartSize.Bounds.Height, min ?? 0D, max ?? 0D, ChartRenderer.TextMeasurer, options); + } + else + { + if (ax.AxisType==eAxisType.Val) + { + res = DateAxisScaleCalculator.Calculate(min ?? 0D, max ?? 0D, options); + } + else + { + res = DateAxisScaleCalculator.CalculateByWidthAllowDiagonal(min ?? 0D, max ?? 0D, ChartRenderer.TextMeasurer, options); + } + } + + orientation = res.TextOrientation; + dateUnit = res.MajorDateUnit; + majorUnit = res.MajorInterval; + var dt = DateTime.FromOADate(res.Min); + var maxDt = DateTime.FromOADate(res.Max); + IsDateScale = (dateUnit != eTimeUnit.Days || majorUnit > 1) && values.Count > 31; + + while (dt <= maxDt) + { + l.Add(dt); + switch(res.MajorDateUnit ?? eTimeUnit.Days) + { + case eTimeUnit.Years: + dt = dt.AddYears((int)res.MajorInterval); + break; + case eTimeUnit.Months: + dt = dt.AddMonths((int)res.MajorInterval); + break; + case eTimeUnit.Days: + dt = dt.AddDays((int)res.MajorInterval); + break; + } + } + + min = res.Min; + max = res.Max; + } + else + { + var res = ValueAxisScaleCalculator.Calculate(min ?? 0, max ?? 0, length, options); + for (var v = res.Min; v <= res.Max; v += res.MajorInterval) + { + l.Add(v); + } + + min = res.Min; + max = res.Max; + majorUnit = res.MajorInterval; + dateUnit= null; + orientation = eTextOrientation.Horizontal; + } + + return l; + } + + /// + /// Adjust the min and max values based on the values in the chart objects, such as trendlines. This is needed to make sure that the trendlines are visible in the chart and not cut off because the axis scale is based on the data series only. + /// + /// The min value to adjust. + /// The max value to adjust. + private void AdjustminMaxFromChartObjects(ExcelChartAxisStandard ax, ref double? min, ref double? max) + { + foreach (var drawer in ChartRenderer.Plotarea.ChartTypeDrawers) + { + if (drawer.IsOnAxis(ax)) + { + if (drawer.SupportsTrendlines) + { + foreach (var tl in drawer.Trendlines) + { + foreach (var c in tl.Coordinates) + { + if (min > c.Y) + { + min = c.Y; + } + if (max < c.Y) + { + max = c.Y; + } + } + } + } + if(drawer.SupportsErrorBars && drawer.ErrorBars!=null) + { + foreach(var v in drawer.ErrorBars.Values) + { + if (v[0] < min) + { + min = v[0]; + } + if (v[2] > max) + { + max = v[2]; + } + } + + } + } + } + } + + private bool ShouldHavePadding() + { + return Axis.AxisType == eAxisType.Val || (Chart.IsTypeLine() && Axis.AxisType == eAxisType.Date); + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs new file mode 100644 index 0000000000..647c3ce066 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs @@ -0,0 +1,45 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using System.Collections.Generic; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartAxisTextBoxes : ChartDrawingObject + { + internal ChartAxisTextBoxes(ChartRenderer chart) : base(chart) + { + } + + internal List TextBoxes + { + get; + set; + }=new List(); + + public override void AppendRenderItems(List renderItems) + { + if (TextBoxes != null && TextBoxes.Count > 0) + { + foreach (var tb in TextBoxes) + { + tb.AppendRenderItems(renderItems); + } + } + + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartDrawingObject.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartDrawingObject.cs new file mode 100644 index 0000000000..ae9f40a9b5 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartDrawingObject.cs @@ -0,0 +1,129 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Utils.TypeConversion; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartAreaRenderer : ChartDrawingObject + { + public ChartAreaRenderer(ChartRenderer sc, SvgRenderOptions options) : base(sc) + { + if(options.Size.Width.HasValue) + { + sc.Bounds.Width = options.Size.WidthPixels; + } + if (options.Size.Height.HasValue) + { + sc.Bounds.Height = options.Size.HeightPixels; + } + + Rectangle = new RectRenderItem(sc.Bounds); + } + + public override void AppendRenderItems(List renderItems) + { + renderItems.Add(Rectangle); + } + } + internal abstract class ChartDrawingObject : DrawingObject + { + internal ChartRenderer ChartRenderer; + internal ExcelChart Chart => (ExcelChart)ChartRenderer.Drawing; + + internal RenderContext RenderContext => ChartRenderer.RenderContext; + internal ChartDrawingObject(ChartRenderer chart) + { + ChartRenderer = chart; + //Fixes null ref but might be inaccurate for some objects... + Rectangle = new RectRenderItem(chart.Bounds); + } + internal void SetMargins(ExcelTextBody tb) + { + tb.GetInsetsOrDefaults(out double l, out double r, out double t, out double b); + LeftMargin = l; + RightMargin = r; + TopMargin = t; + BottomMargin = b; + } + internal double LeftMargin { get; set; } + internal double RightMargin { get; set; } + internal double TopMargin { get; set; } + internal double BottomMargin { get; set; } + internal virtual RectRenderItem Rectangle { get; set; } + protected static RectRenderItem GetRectFromManualLayout(ChartRenderer sc, ExcelLayout layout, BoundingBox parent=null) + { + var bounds = parent ?? sc.Bounds; + var rect = new RectRenderItem(sc.ChartArea.Rectangle.Bounds); + var ml = layout.ManualLayout; + if (ml.LeftMode == eLayoutMode.Edge) + { + rect.Left = bounds.Width * (float)(layout.ManualLayout.Left ?? 0D) / 100; + } + else + { + rect.Left = bounds.Width * (float)(ml.Left ?? 0D) / 100; + //TODO:Add factor from default position + } + + //Width is always factor. + rect.Width = bounds.Width * ml.GetWidth() / 100; + + if (ml.LeftMode == eLayoutMode.Edge) + { + rect.Top = bounds.Height * (float)(layout.ManualLayout.Top ?? 0D) / 100; + } + else + { + rect.Top = bounds.Height * (float)(ml.Top ?? 0D) / 100; + //TODO:Add factor from default position + } + //Height is always factor. + rect.Height = bounds.Height * ml.GetHeight() / 100; + return rect; + } + /// + /// Get the X serie values. If the values are not numeric, return a serie with the index values (1,2,3,...). Trendline calculation requires numeric X values, but Excel allows non-numeric X values for trendlines, in which case it uses the index values as X for calculation. + /// + /// Input values + /// Output doubles + internal List GetXSerie(List xSerie) + { + var l = new List(); + for (int i = 0; i < xSerie.Count; i++) + { + if (ConvertUtil.IsExcelNumeric(xSerie[i])) + { + l.Add(ConvertUtil.GetValueDouble(xSerie[i])); + } + else + { + return xSerie.Select((x, index) => (double)(index + 1)).ToList(); + } + } + return l; + } + + + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs new file mode 100644 index 0000000000..5ebbbf2a06 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs @@ -0,0 +1,832 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.Utils; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Renderer.Chart; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartLegendRenderer : ChartDrawingObject + { + + List _seriesHeadersMeasure = new List(); + ITextMeasurer _ttMeasurer; + const float MarginIconText = 1.5f; + const float MarginHeight = 7.5f; + const float LineLength = 21; + const float MinBarLength = 4; + float _marginItemsWidth; + + double _maxWidth, _maxHeight; + internal ChartLegendRenderer(ChartRenderer sc, bool isDataLabelLegend = false) : base(sc) + { + var mf = Chart.Font.GetMeasureFont(); + var shaper = RenderContext.FontEngine.GetShaperForFont(mf); + var _ttMeasurer = new OpenTypeFontTextMeasurer(shaper); + + if (sc.Chart.HasLegend == false && isDataLabelLegend == false || sc.Chart.Series.Count == 0) + { + return; + } + + var l = ((ExcelChartStandard)sc.Chart).Legend; + + LeftMargin = RightMargin = 3; //4px + TopMargin = BottomMargin = 3; //4px + _marginItemsWidth = mf.Size / 2; //We use half the size of the font as margin between items. + switch (l.Position) + { + case eLegendPosition.Top: + case eLegendPosition.Bottom: + _maxWidth = sc.ChartArea.Rectangle.Width * 0.85; + _maxHeight = sc.ChartArea.Rectangle.Height * 0.6; + break; + default: + _maxWidth = sc.ChartArea.Rectangle.Width * 0.6; + _maxHeight = sc.ChartArea.Rectangle.Height * 0.85; + break; + } + double entryWidth, entryHeight; + + Rectangle = GetLegendRectangleAndEntrySize(l, out entryWidth, out entryHeight); + + if (l.Layout.HasLayout) //Manual layout will override the position and size of legend, but not the entry size which is used for calculating the position of legend entries. + { + Rectangle = GetRectFromManualLayout(sc, l.Layout); + } + + //Bounds.Left = Rectangle.Left; + //Bounds.Top = Rectangle.Top; + //Bounds.Width = Rectangle.Width; + //Bounds.Height = Rectangle.Height; + //Rectangle.Bounds.Left = Rectangle.Bounds.Top = 0; + + Rectangle.SetDrawingPropertiesFill(sc.Theme, l.Fill, sc.Chart.StyleManager.Style?.Title.FillReference.Color, false); + Rectangle.SetDrawingPropertiesBorder(sc.Theme, l.Border, sc.Chart.StyleManager.Style?.Title.BorderReference.Color, l.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + var pSls = SetLegendSeries(entryWidth, entryHeight); + SetLegendTrendlines(entryWidth, entryHeight, pSls); + } + + + private RectRenderItem GetLegendRectangleAndEntrySize(ExcelChartLegend l, out double entryWidth, out double entryHeight) + { + //var rect = new RectRenderItem(RectanBounds); + var rect = Rectangle = new RectRenderItem(ChartRenderer.Bounds); + var widest = 0d; + var highest = 0d; + var index = 0; + + //Find the widest and hightest legend entry, and calculate the total width and hight of the legend based on the orientation. + foreach (var ct in Chart.PlotArea.ChartTypes) + { + if (ct.GetType() == typeof(ExcelPieChart)) + { + //Pie chart cares only about first series + if (ct.Series[0].GetType() == typeof(ExcelPieChartSerie)) + { + var ps = (ExcelPieChartSerie)ct.Series[0]; + var catValues = DrawingExtensions.LoadSeriesValues(ct, ps.XSeries, ps.NumberLiteralsX, ps.StringLiteralsX); + + //Excel fallsback to index + 1 if no literals and no series + if (catValues == null) + { + catValues = new List(); + foreach (var dp in ps.DataPoints) + { + catValues.Add($"{dp.Index + 1}"); + } + } + for (int i = 0; i < catValues.Count; i++) + { + var text = catValues[i].ToString(); + GetSerieSize(l, index, text, ref widest, ref highest); + index++; + } + } + //Skip the rest + break; + } + else + { + foreach (var s in ct.Series) + { + var text = s.GetHeaderText(index); + GetSerieSize(l, index, text, ref widest, ref highest); + index++; + } + } + } + + //Trendlines also get legend entries, but they should appear after the series name. + var trIndex = 0; + foreach (var ct in Chart.PlotArea.ChartTypes) + { + foreach (var s in ct.Series) + { + foreach (var tl in s.TrendLines) + { + var text = tl.GetName(index); + GetSerieSize(l, trIndex, text, ref widest, ref highest); + trIndex++; + } + } + } + + index += trIndex; + + var maxIconLength = GetMaxIconLength(Chart, highest); + entryWidth = maxIconLength + MarginIconText + widest; + entryHeight = highest; + + switch (l.Position) + { + case eLegendPosition.Top: + case eLegendPosition.Bottom: + var fullLength = LeftMargin + entryWidth * index + _marginItemsWidth * (index - 1) + RightMargin; + if(fullLength > _maxWidth) + { + var height = entryHeight * 0.25; + var widestLine = 0D; + var width = LeftMargin + entryWidth; + + for(int i = 0; i < index; i++) + { + if (width + entryWidth + RightMargin > _maxWidth) + { + height += entryHeight * 1.25; + if (width + RightMargin > widestLine) + { + widestLine = width + RightMargin; + } + width = RightMargin + entryWidth; + } + else + { + width += entryWidth + _marginItemsWidth; + } + } + + //height+= BottomMargin; + rect.Width = Math.Max(widestLine, width); + rect.Height = height + entryHeight * 1.25; + } + else + { + rect.Width = fullLength; + rect.Height = entryHeight * 1.5; + } + rect.Left = (ChartRenderer.ChartArea.Rectangle.Width - rect.Width) / 2; + if (l.Position == eLegendPosition.Top) + { + rect.Top = ChartRenderer.Title.Rectangle.Bottom + MarginHeight; + } + else + { + rect.Top = ChartRenderer.ChartArea.Rectangle.Height - rect.Height - BottomMargin; + } + break; + case eLegendPosition.Right: + case eLegendPosition.TopRight: + case eLegendPosition.Left: + rect.Width = LeftMargin + entryWidth + RightMargin; + rect.Height = TopMargin + (entryHeight * index) + ((index - 1) * entryHeight * 0.5) + BottomMargin; //use margin as 50% of the entry height and to the top and the bottom.; + + if (rect.Height > _maxHeight) + { + rect.Height = _maxHeight; + } + + if (l.Position == eLegendPosition.Right || + l.Position == eLegendPosition.TopRight) + { + rect.Left = ChartRenderer.ChartArea.Rectangle.Width - rect.Width - TopMargin; + } + else + { + rect.Left = LeftMargin + 2; + } + if (l.Position == eLegendPosition.Left || + l.Position == eLegendPosition.Right) + { + //Will be set when the plotarea width is calculated. + //rect.Top = sc.ChartArea.Rectangle.Height / 2 - rect.Height / 2; + } + else + { + if (ChartRenderer.Title == null) + { + rect.Top = 8 + 8; + } + else + { + rect.Top = ChartRenderer.Title.Rectangle.Height + 8 + 8; //Height + Margin Top and Bottom Title + } + } + break; + } + + return rect; + } + + private void GetSerieSize(ExcelChartLegend l, int index, string text, ref double widest, ref double highest) + { + var entry = l.Entries.FirstOrDefault(x => x.Index == index); + ExcelTextFont font; + MeasurementFont mf; + if (entry == null || entry.Font.IsEmpty) + { + font = l.Font; + mf = l.Font.GetMeasureFont(); + } + else + { + font = entry.Font; + mf = entry.Font.GetMeasureFont(); + } + + if (_ttMeasurer == null) + { + _ttMeasurer = new OpenTypeFontTextMeasurer(RenderContext.FontEngine.GetShaperForFont(mf)); + } + + var tm = _ttMeasurer.MeasureText(text, mf); + _seriesHeadersMeasure.Add(tm); + + if (tm.Width > widest) + { + widest = tm.Width; + } + + if (tm.Height > highest) + { + highest = tm.Height; + } + } + + private double GetMaxIconLength(ExcelChart ct, double heighestText) + { + var maxIconLength = 0D; + foreach(var c in ct.PlotArea.ChartTypes) + { + var il = GetIconLength(c, heighestText); + if (il > maxIconLength) + { + maxIconLength = il; + } + } + return maxIconLength; + } + private double GetIconLength(ExcelChart c, double highestText) + { + return c.IsTypeLine() ? LineLength : Math.Max(MinBarLength, highestText * 0.4); + } + + + internal DrawingLegendSerie SetLegendSeries(double entryWidth, double entryHeight) + { + int index = 0; + DrawingLegendSerie pSls = null; + var pos = Chart.Legend.Position; + var maxIconLength = GetMaxIconLength(Chart, entryHeight); + foreach (var ct in Chart.PlotArea.ChartTypes) + { + int ix, end; + if (ct.IsTypeBar()) + { + ix = ct.Series.Count - 1; + end = -1; + } + else + { + ix = 0; + end = ct.Series.Count; + } + + while (ix != end) + { + var s = ct.Series[ix]; + var sls = new DrawingLegendSerie(); + switch (ct.ChartType) + { + case eChartType.Line: + case eChartType.LineMarkers: + case eChartType.LineMarkersStacked: + case eChartType.LineMarkersStacked100: + case eChartType.LineStacked: + case eChartType.LineStacked100: + SetLineLegend(ct, index, pSls, pos, s, sls, entryWidth, entryHeight, maxIconLength); + break; + case eChartType.ColumnClustered: + case eChartType.ColumnStacked: + case eChartType.ColumnStacked100: + case eChartType.BarClustered: + case eChartType.BarStacked: + case eChartType.BarStacked100: + SetBarLegend(ct, index, pSls, pos, s, sls, entryWidth, entryHeight, maxIconLength); + break; + case eChartType.Pie: + case eChartType.PieExploded: + if (ix == 0) + { + SetPieLegend(ct, index, pSls, pos, s, sls, entryWidth, entryHeight, maxIconLength); + pSls = null; + sls = null; + } + break; + default: + break; + } + if (Chart.Legend.Position == eLegendPosition.Top || + Chart.Legend.Position == eLegendPosition.Bottom) + { + //if (sls.Textbox.Bounds.Bottom > Rectangle.Bottom) + //{ + // break; + //} + } + else + { + if (sls.Textbox.Bounds.Bottom > Rectangle.Height) + { + break; + } + } + if (sls != null) + { + SeriesIcon.Add(sls); + } + //SeriesIcon.Add(sls); + pSls = sls; + //else + //{ + // pSls = null; + //} + index++; + if (ix < end) + { + ix++; + } + else + { + ix--; + } + } + } + return pSls; + // if (Chart.Legend.Position == eLegendPosition.Top || + // Chart.Legend.Position == eLegendPosition.Bottom) + // { + // if (sls.Textbox.Bounds.Bottom > Rectangle.Bottom) + // { + // break; + // } + // } + // else + // { + // if (sls.Textbox.Bounds.Bottom > Rectangle.Height) + // { + // break; + // } + // } + // SeriesIcon.Add(sls); + // pSls = sls; + // index++; + // if(ix Rectangle.Height) + { + return; + } + + SeriesIcon.Add(sls); + pSls = sls; + index++; + + } + if (ix < end) + { + ix++; + } + else + { + ix--; + } + } + } + } + private void SetTrendlineLegend(ExcelChart ct, int serieIndex, int entryIndex, DrawingLegendSerie pSls, eLegendPosition pos, ExcelChartTrendline tl, DrawingLegendSerie sls, double entryWidth, double entryHeight) + { + + var si = GetTrendLineSeriesIcon(ct, tl, pSls, entryWidth, entryHeight); + sls.SeriesIcon = si; + + var tbLeft = si.X1 + LineLength + MarginIconText; + var tbTop = si.Y2 - entryHeight * 0.5; //TODO:Should probably be font ascent + double tbWidth; + tbWidth = Rectangle.Bounds.Width - tbLeft; + + var tbHeight = entryHeight; + sls.Textbox = new DrawingTextBody(RenderContext, Chart, Rectangle.Bounds, tbLeft, tbTop, tbWidth, tbHeight, false, true); + + var entry = Chart.Legend.Entries.FirstOrDefault(x => x.Index == entryIndex); + var headerText = tl.GetName(serieIndex); + if (entry == null || entry.Font.IsEmpty) + { + sls.Textbox.ImportParagraph(Chart.Legend.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + else + { + sls.Textbox.ImportParagraph(entry.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + } + + + private void SetPieLegend(ExcelChart ct, int index, DrawingLegendSerie pSls, eLegendPosition pos, ExcelChartSerie s, DrawingLegendSerie sls, double entryWidth, double entryHeight, double maxIconLength) + { + var ps = (ExcelPieChartSerie)s; + pSls = null; + + //Pie chart only cares about series 0 + var series = ct.Series[0]; + var catSeries = series.XSeries; + var catValues = DrawingExtensions.LoadSeriesValues(ct, catSeries, series.NumberLiteralsX, series.StringLiteralsX); + //Excel fallsback to index + 1 if no literals and no series + if (catValues == null) + { + catValues = new List(); + foreach (var dp in ps.DataPoints) + { + catValues.Add($"{dp.Index + 1}"); + } + } + + double lastWidth = 0; + double totalWidth = 0; + + for (int i = 0; i < catValues.Count; i++) + { + var tm = _seriesHeadersMeasure[index + i]; + //Step 1: Retrieve Icon + + var si = GetPieSeriesIcon(ct, ps, pSls, lastWidth, entryHeight, i); + sls = new DrawingLegendSerie(); + var tbLeft = si.Left + maxIconLength + MarginIconText; + var tbTop = si.Top - ((entryHeight) / 2); + + double tbWidth; + + if(i != catValues.Count -1) + { + tbWidth = Rectangle.Bounds.Width - tbLeft; + } + else + { + tbWidth = Rectangle.Bounds.Width; + } + + var tbHeight = tm.Height; + sls.Textbox = new DrawingTextBody(RenderContext, Chart, Rectangle.Bounds, tbLeft, tbTop, tbWidth, tbHeight, false, true); + //var para = sc.Chart.Legend.TextBody.Paragraphs.FirstOrDefault(); + sls.Textbox.ImportParagraph(Chart.Legend.TextBody.Paragraphs.FirstOrDefault(), 0, catValues[i].ToString()); + sls.SeriesIcon = si; + sls.Textbox.RecalculateParagraphs(); + + tbWidth = sls.Textbox.Width; + + lastWidth = tbWidth + si.Width; + + totalWidth += tbWidth + si.Width + maxIconLength + MarginIconText; + + var dp = ps.DataPoints[i]; + + sls.SeriesIcon.SetDrawingPropertiesFill(ChartRenderer.Theme, dp.Fill, ct.As.Chart.PieChart.StyleManager.Style?.DataPoint.FillReference.Color); + sls.SeriesIcon.SetDrawingPropertiesBorder(ChartRenderer.Theme, dp.Border, ct.As.Chart.PieChart.StyleManager.Style?.DataPoint.BorderReference.Color, true); + sls.SeriesIcon.SetDrawingPropertiesEffects(ChartRenderer.Theme, dp.Effect); + + SeriesIcon.Add(sls); + pSls = sls; + } + + foreach(var icon in SeriesIcon) + { + icon.SeriesIcon.Bounds.Top = icon.SeriesIcon.Bounds.Top - ((entryHeight) / 4); + } + + Rectangle.Bounds.Width = SeriesIcon.Last().Textbox.Bounds.GetGlobalBoundingbox().Right - SeriesIcon[0].SeriesIcon.Bounds.GlobalLeft + 4; + Rectangle.Bounds.Left = (ChartRenderer.Bounds.Width / 2) - (totalWidth/2); + pSls = null; + sls = null; + } + + private void SetLineLegend(ExcelChart ct, int index, DrawingLegendSerie pSls, eLegendPosition pos, ExcelChartSerie s, DrawingLegendSerie sls, double entryWidth, double entryHeight, double maxIconLength) + { + var ls = (ExcelLineChartSerie)s; + + var si = GetLineSeriesIcon(ct, ls, pSls, entryWidth, entryHeight); + sls.SeriesIcon = si; + + var tbLeft = si.X1 + maxIconLength + MarginIconText; + var tbTop = si.Y2 - entryHeight * 0.5; + var tbWidth = Rectangle.Bounds.Width - tbLeft; + + var tbHeight = entryHeight; + sls.Textbox = new DrawingTextBody(RenderContext, Chart, Rectangle.Bounds, tbLeft, tbTop, tbWidth, tbHeight, false, true); + + var entry = Chart.Legend.Entries.FirstOrDefault(x => x.Index == index); + var headerText = s.GetHeaderText(index); + if (entry == null || entry.Font.IsEmpty) + { + sls.Textbox.ImportParagraph(Chart.Legend.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + else + { + //sls.Textbox.AddText(s.GetHeaderText(), entry.Font); + sls.Textbox.ImportParagraph(entry.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + + if (ls.HasMarker() && ls.Marker.Style != eMarkerStyle.None) + { + var l = sls.SeriesIcon as LineRenderItem; + var x = l.X1 + (l.X2 - l.X1) / 2; + var y = l.Y1; + sls.MarkerIcon = LineMarkerHelper.GetMarkerItem(ChartRenderer, ls, x, y, true); + if ((ls.Marker.Style == eMarkerStyle.Plus || ls.Marker.Style == eMarkerStyle.X || ls.Marker.Style == eMarkerStyle.Star) && + ls.Marker.Fill.IsEmpty == false) + { + sls.MarkerBackground = LineMarkerHelper.GetMarkerBackground(ChartRenderer, ls, x, y, true); + } + else + { + sls.MarkerBackground = null; + } + } + } + + private void SetBarLegend(ExcelChart ct, int index, DrawingLegendSerie pSls, eLegendPosition pos, ExcelChartSerie s, DrawingLegendSerie sls, double entryWidth, double entryHeight, double maxIconLength) + { + var bs = (ExcelBarChartSerie)s; + var tm = _seriesHeadersMeasure[index]; + var si = GetBarSeriesIcon(ct, bs, pSls, entryWidth, entryHeight); + sls.SeriesIcon = si; + + var tbLeft = si.Left + maxIconLength + MarginIconText; + var tbTop = si.Top - (entryHeight - si.Height) / 2; + double tbWidth; + + tbWidth = Rectangle.Bounds.Width - tbLeft; + + var tbHeight = tm.Height; + sls.Textbox = new DrawingTextBody(RenderContext, Chart, Rectangle.Bounds, tbLeft, tbTop, tbWidth, tbHeight, false, true); + //sls.Textbox.Bounds.Left = si.Bottom + MarginIconText; + + var entry = Chart.Legend.Entries.FirstOrDefault(x => x.Index == index); + var headerText = s.GetHeaderText(index); + if (entry == null || entry.Font.IsEmpty) + { + //sls.Textbox.AddText(s.GetHeaderText(), sc.Chart.Legend.Font); + sls.Textbox.ImportParagraph(Chart.Legend.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + else + { + //sls.Textbox.AddText(s.GetHeaderText(), entry.Font); + sls.Textbox.ImportParagraph(entry.TextBody.Paragraphs.FirstOrDefault(), 0, headerText); + } + } + + private LineRenderItem GetLineSeriesIcon(ExcelChart ct, ExcelChartStandardSerie cStandardSerie, DrawingLegendSerie pSls, double entryWidth, double entryHeight) + { + var line = new LineRenderItem(Rectangle.Bounds); + line.SetDrawingPropertiesFill(ChartRenderer.Theme, cStandardSerie.Fill, Chart.StyleManager.Style?.SeriesLine.FillReference.Color); + line.SetDrawingPropertiesBorder(ChartRenderer.Theme, cStandardSerie.Border, Chart.StyleManager.Style?.SeriesLine.BorderReference.Color, cStandardSerie.Border.Fill.Style != eFillStyle.NoFill, 0.75); + double iconTop = 0, iconLeft = 0; + pSls?.GetIconTopLeft(out iconTop, out iconLeft); + + GetItemPosition(pSls, entryWidth, entryHeight, iconLeft, iconTop, out double x, out double y); + + line.X1 = x; + line.X2 = x + LineLength; + line.Y1 = y; + line.Y2 = y; + line.LineCap = LineCap.Round; + + return line; + } + private LineRenderItem GetTrendLineSeriesIcon(ExcelChart ct, ExcelChartTrendline tl, DrawingLegendSerie pSls, double entryWidth, double entryHeight) + { + var line = new LineRenderItem(Rectangle.Bounds); + line.SetDrawingPropertiesFill(ChartRenderer.Theme, tl.Fill, Chart.StyleManager.Style?.Trendline.FillReference.Color); + line.SetDrawingPropertiesBorder(ChartRenderer.Theme, tl.Border, Chart.StyleManager.Style?.Trendline.BorderReference.Color, tl.Border.Fill.Style != eFillStyle.NoFill, 0.75); + double iconTop = 0, iconLeft = 0; + pSls?.GetIconTopLeft(out iconTop, out iconLeft); + + GetItemPosition(pSls, entryWidth, entryHeight, iconLeft, iconTop, out double x, out double y); + + line.X1 = x; + line.Y1 = y; + line.X2 = x + LineLength; + line.Y2 = y; + line.LineCap = LineCap.Round; + + return line; + } + + private RectRenderItem GetPieSeriesIcon(ExcelChart ct, ExcelPieChartSerie pcS, DrawingLegendSerie pSls, double entryWidth, double entryHeight, int i) + { + var item = new RectRenderItem(Rectangle.Bounds); + var pt = pcS.DataPoints[i]; + + var iconHeight = GetIconLength(ct, entryHeight); + var icon = pSls?.SeriesIcon as RectRenderItem; + + GetItemPosition(pSls, entryWidth, entryHeight, icon?.Left ?? 0D, icon?.Top ?? 0D, out double x, out double y); + + item.LineCap = LineCap.Round; + item.Left = x; + if (pSls != null && (Chart.Legend.Position == eLegendPosition.Left || Chart.Legend.Position == eLegendPosition.Right)) + { + item.Top = y + (entryHeight - iconHeight) / 2; + } + else + { + item.Top = y; + } + //item.Top = y; + item.Width = iconHeight; + item.Height = iconHeight; + + item.SetDrawingPropertiesFill(ChartRenderer.Theme, pcS.Fill, Chart.StyleManager.Style?.SeriesLine.FillReference.Color); + item.SetDrawingPropertiesBorder(ChartRenderer.Theme, pcS.Border, Chart.StyleManager.Style?.SeriesLine.BorderReference.Color, pcS.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + return item; + } + + + private RectRenderItem GetBarSeriesIcon(ExcelChart ct, ExcelChartStandardSerie cStandardSerie, DrawingLegendSerie pSls, double entryWidth, double entryHeight) + { + var item = new RectRenderItem(Rectangle.Bounds); + var iconHeight = GetIconLength(ct, entryHeight); + //var icon = pSls?.SeriesIcon as RectRenderItem; + double iconTop = 0, iconLeft = 0; + pSls?.GetIconTopLeft(out iconTop, out iconLeft); + + GetItemPosition(pSls, entryWidth, entryHeight, iconLeft, iconTop + (iconHeight / 2), out double x, out double y); + + item.LineCap = LineCap.Round; + item.Left = x; + if(pSls !=null && (Chart.Legend.Position == eLegendPosition.Left || Chart.Legend.Position == eLegendPosition.Right)) + { + item.Top = y - iconHeight / 2; + } + else + { + item.Top = y - iconHeight / 2; + } + //item.Top = y; + item.Width = iconHeight; + item.Height = iconHeight; + + item.SetDrawingPropertiesFill(ChartRenderer.Theme, cStandardSerie.Fill, Chart.StyleManager.Style?.SeriesLine.FillReference.Color); + item.SetDrawingPropertiesBorder(ChartRenderer.Theme, cStandardSerie.Border, Chart.StyleManager.Style?.SeriesLine.BorderReference.Color, cStandardSerie.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + return item; + } + + private double GetItemPosition(DrawingLegendSerie pSls, double entryWidth, double entryHeight, double iconLeft, double iconCenter, out double x, out double y) + { + var topOffset = 0D; + if (Chart.Legend.Position == eLegendPosition.Top || + Chart.Legend.Position == eLegendPosition.Bottom) + { + if (pSls != null && iconLeft + entryWidth * 2 + _marginItemsWidth + RightMargin > _maxWidth) + { + topOffset += entryHeight * 1.25; + x = LeftMargin; + } + else + { + if (pSls == null) + { + x = (float)LeftMargin; + } + else + { + x = iconLeft + entryWidth + _marginItemsWidth; + } + } + + if (pSls == null) + { + y = TopMargin + entryHeight / 2; + } + else + { + y = iconCenter + topOffset; + } + + + } + else + { + if (pSls == null) + { + y = TopMargin + entryHeight / 2; + } + else + { + y = iconCenter + entryHeight * 1.5; + } + x = LeftMargin; + + } + + return topOffset; + } + + public override void AppendRenderItems(List renderItems) + { + var groupItem = new GroupRenderItem(ChartRenderer.Bounds); + groupItem.Top = Rectangle.Bounds.Top; + groupItem.Left = Rectangle.Bounds.Left; + renderItems.Add(groupItem); + + //The rectangle is position using the group transform, so we need to set the rectangle position to 0,0 + Rectangle.Bounds.Top = 0; + Rectangle.Bounds.Left = 0; + + groupItem.RenderItems.Add(Rectangle); + foreach(var s in SeriesIcon) + { + if(s.SeriesIcon != null) groupItem.RenderItems.Add(s.SeriesIcon); + if(s.MarkerBackground != null) groupItem.RenderItems.Add(s.MarkerBackground); + if (s.MarkerIcon != null) groupItem.RenderItems.Add(s.MarkerIcon); + //renderItems.Add(s.Textbox); + if(s.Textbox != null) s.Textbox.AppendRenderItems(groupItem.RenderItems); + } + } + + public List SeriesIcon { get; } = new List(); + + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs new file mode 100644 index 0000000000..b9c0e1f9c5 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs @@ -0,0 +1,230 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.Svg.Chart; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartPlotareaRenderer : ChartDrawingObject + { + public ChartPlotareaRenderer(ChartRenderer sc) : base(sc) + { + + } + public List ChartTypeDrawers { get; set; } + public GroupRenderItem Group { get; private set; } + internal void SetPlotAreaRectangle() + { + var pa = Chart.PlotArea; + TopMargin = BottomMargin = LeftMargin = RightMargin = 10.5; //14px + var rect = new RectRenderItem(ChartRenderer.Bounds); + if (pa.Layout.HasLayout) + { + rect = GetRectFromManualLayout(ChartRenderer, pa.Layout); + } + else + { + rect.Top = GetPlotAreaTop(); + rect.Left = GetPlotAreaLeft(); + rect.Width = GetPlotAreaWidth(rect); + rect.Height = GetPlotAreaHeight(rect); + } + + Group = new GroupRenderItem(ChartRenderer.Bounds); + Group.Bounds.Top = rect.Top; + Group.Bounds.Left = rect.Left; + rect.Top = rect.Left = 0; + Group.RenderItems.Add(rect); + + if(ChartRenderer.Legend!=null && Chart.Legend.Position == eLegendPosition.Right || + Chart.Legend.Position == eLegendPosition.Left) + { + ChartRenderer.Legend.Rectangle.Top = Group.Top + rect.Height / 2 - ChartRenderer.Legend.Rectangle.Height / 2; + } + + rect.SetDrawingPropertiesFill(ChartRenderer.Theme, pa.Fill, ChartRenderer.Chart.StyleManager.Style?.PlotArea.FillReference.Color, false, ChartRenderer.Theme.ColorScheme.Light1); + rect.SetDrawingPropertiesBorder(ChartRenderer.Theme, pa.Border, ChartRenderer.Chart.StyleManager.Style?.PlotArea.BorderReference.Color, pa.Border.Fill.Style != eFillStyle.NoFill, 0.75); + Rectangle = rect; + } + + private double GetPlotAreaHeight(RectRenderItem rect) + { + var bottomAxis = GetAxisActualByPosition(eActualAxisPosition.Bottom); + double vaHeight = 0; + if (bottomAxis!=null) + { + var bottomSecondAxis = GetAxisActualByPosition(eActualAxisPosition.BottomSecond); + vaHeight = (bottomAxis.Rectangle?.Height ?? 0D) + (bottomAxis.Title?.TextBox?.GetActualHeight() ?? 0D) + (bottomSecondAxis?.Rectangle?.Height ?? 0D); + } + if (Chart.Legend?.Position == eLegendPosition.Bottom) + { + vaHeight += ChartRenderer.Legend.Rectangle.Height + ChartRenderer.Legend.TopMargin; + } + return ChartRenderer.Bounds.Height - rect.GlobalTop - vaHeight - BottomMargin; + } + + private double GetPlotAreaWidth(RectRenderItem rect) + { + var rightAxis = GetAxisActualByPosition(eActualAxisPosition.Right); + var rightSecondAxis = GetAxisActualByPosition(eActualAxisPosition.RightSecond); + var lp = ChartRenderer.Chart.Legend?.Position; + var right = ((lp == eLegendPosition.Right || lp == eLegendPosition.TopRight) && ChartRenderer.Legend != null ? + ChartRenderer.Legend.Rectangle.Bounds.GlobalLeft - RightMargin : + ChartRenderer.ChartArea.Rectangle.Width - RightMargin); + + + double rightAxisWidth; + if (rightAxis == null) + { + rightAxisWidth = 0; + } + else + { + rightAxisWidth = (rightAxis.Title?.TextBox.GetActualWidth() ?? 0D) + (rightAxis.Rectangle?.Width ?? 0D) + (rightSecondAxis?.Rectangle?.Width ?? 0D); + } + + var width = right - rightAxisWidth - rect.GlobalLeft; + //Reserve space for the last label that will be on the tick label instead of Middle of the category. + if (ChartRenderer.HorizontalAxis != null && ChartRenderer.VerticalAxis.Axis.CrossBetween == eCrossBetween.MidCat) + { + var minusPA = width / ChartRenderer.HorizontalAxis.AxisValues.Count / 2; + if (minusPA > rightAxisWidth) + { + rightAxisWidth = minusPA; + } + } + if (ChartRenderer.SecondHorizontalAxis != null && ChartRenderer.SecondVerticalAxis.Axis.CrossBetween == eCrossBetween.MidCat) + { + var minusSA = width / ChartRenderer.SecondHorizontalAxis.AxisValues.Count / 2; + if (minusSA > rightAxisWidth) + { + rightAxisWidth = minusSA; + } + } + + return right - rightAxisWidth-rect.GlobalLeft; + } + private double GetPlotAreaLeft() + { + var left = LeftMargin; + if(ChartRenderer.Chart.Legend?.Position == eLegendPosition.Left) + { + left += ChartRenderer.Legend.Rectangle.Bounds.Width + ChartRenderer.Legend.RightMargin; + } + + var leftAxis = GetAxisActualByPosition(eActualAxisPosition.Left); + var leftSecondAxis = GetAxisActualByPosition(eActualAxisPosition.LeftSecond); + if (leftAxis == null) + { + leftAxis = GetAxisByPosition(eAxisPosition.Left); + left += leftAxis?.Title?.TextBox.Width ?? 0D; + } + else + { + if (leftAxis.Title!=null) + { + left += leftAxis.Title.TextBox.GetActualWidth(); + } + if (leftAxis.Rectangle != null) + { + left += leftAxis.Rectangle.Width + 1.5; + } + if(leftSecondAxis!=null) + { + left += leftSecondAxis.Rectangle.Width; + } + } + return left; + } + private double GetPlotAreaTop() + { + double haHeight = 0; + var topAxis = GetAxisActualByPosition(eActualAxisPosition.Top); + var topSecondAxis = GetAxisActualByPosition(eActualAxisPosition.TopSecond); + if (topAxis == null) + { + //If the axis is not on the top, we should check if there is an axis that has the position on the top. If there is, we should reserve space for the title of the axis. This can happen when LabelPosition is set to Low and the axis is on the bottom, but the position of the axis is set to top. + topAxis = GetAxisByPosition(eAxisPosition.Top); + haHeight = topAxis?.Title?.Rectangle.Height ?? 0D; + } + else + { + haHeight = (topAxis.Rectangle?.Height ?? 0D) + (topSecondAxis?.Rectangle?.Height ?? 0D) + (topAxis.Title?.TextBox?.GetActualHeight() ?? 0D); + } + + return (Chart.Legend?.Position == eLegendPosition.Top ? ChartRenderer.Legend.Rectangle.Bounds.Bottom : ChartRenderer.Title?.Rectangle?.GlobalBottom ?? 0d) + haHeight + TopMargin; + } + + private ChartAxisRenderer GetAxisActualByPosition(eActualAxisPosition pos) + { + if (ChartRenderer.HorizontalAxis != null && ChartRenderer.HorizontalAxis.Axis.ActualAxisPosition == pos) + { + return ChartRenderer.HorizontalAxis; + } + else if (ChartRenderer.VerticalAxis != null && ChartRenderer.VerticalAxis.Axis.ActualAxisPosition == pos) + { + return ChartRenderer.VerticalAxis; + } + else if (ChartRenderer.SecondHorizontalAxis != null && ChartRenderer.SecondHorizontalAxis.Axis.ActualAxisPosition == pos) + { + return ChartRenderer.SecondHorizontalAxis; + } + else if (ChartRenderer.SecondVerticalAxis != null && ChartRenderer.SecondVerticalAxis.Axis.ActualAxisPosition == pos) + { + return ChartRenderer.SecondVerticalAxis; + } + return null; + } + private ChartAxisRenderer GetAxisByPosition(eAxisPosition pos) + { + if (ChartRenderer.HorizontalAxis != null && ChartRenderer.HorizontalAxis.Axis.AxisPosition == pos) + { + return ChartRenderer.HorizontalAxis; + } + else if (ChartRenderer.VerticalAxis != null && ChartRenderer.VerticalAxis.Axis.AxisPosition == pos) + { + return ChartRenderer.VerticalAxis; + } + else if (ChartRenderer.SecondHorizontalAxis != null && ChartRenderer.SecondHorizontalAxis.Axis.AxisPosition == pos) + { + return ChartRenderer.SecondHorizontalAxis; + } + else if (ChartRenderer.SecondVerticalAxis != null && ChartRenderer.SecondVerticalAxis.Axis.AxisPosition == pos) + { + return ChartRenderer.SecondVerticalAxis; + } + return null; + } + + public override void AppendRenderItems(List renderItems) + { + renderItems.Add(Group); + } + + internal void DrawSeries() + { + foreach (var drawer in ChartTypeDrawers) + { + drawer.DrawSeries(); + } + } + + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs new file mode 100644 index 0000000000..cd93d52462 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs @@ -0,0 +1,234 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using EPPlus.DrawingRenderer.RenderItems; + +namespace EPPlusImageRenderer.Svg +{ + internal class ChartTitleRenderer : ChartDrawingObject + { + ExcelChartTitleStandard _title; + string _titleText; + ChartRenderer _svgChart; + /// + /// + /// + /// + /// + /// + /// If null, this is the main chart title. + internal ChartTitleRenderer(ChartRenderer sc, ExcelChartTitleStandard t, string defaultText, ChartAxisRenderer axis=null) : base(sc) + { + _svgChart = sc; + + //These are hard coded margins for the title box. + LeftMargin = RightMargin = 3; //4px + TopMargin = BottomMargin = 1.5; //2px + LeftMargin = RightMargin = 3; //4px + TopMargin = BottomMargin = 1.5; //2px + + var maxWidth = sc.Bounds.Width * 0.8; + var maxHeight = sc.Bounds.Height / 2D; + _title = t; + if (axis==null) + { + _titleText = GetDefaultChartTitleText(sc, t, defaultText); + } + else + { + if (string.IsNullOrEmpty(t.DisplayedText) == false) + { + _titleText = t.DisplayedText; + } + else + { + _titleText = t.Font.GetCapitalizedText(defaultText); + } + } + + if (t.Layout.HasLayout) //Only for the main chart title, axis titles don't support manual layout in Excel. + { + + InitTextBox(maxWidth, maxHeight); + var mr = GetRectFromManualLayout(sc, t.Layout); + TextBox.Top = mr.Top; + TextBox.Left = mr.Left; + } + else + { + if (axis == null) + { + InitTextBox(maxWidth, maxHeight); + TextBox.Top = (float)6; //6 point for the chart title standard offset. + TextBox.Left = (float)(sc.Bounds.Width - TextBox.Width) / 2; + } + else + { + var isVertical = axis.Axis.IsVertical; + maxWidth = sc.Bounds.Width * (isVertical ? 0.2 : 0.8); //Max Width. + maxHeight = sc.Bounds.Height * (isVertical ? 0.8 : 0.2); //Max Height. + + InitTextBox(maxWidth, maxHeight); + SetAxisTitleRect(sc, axis); + } + } + + Rectangle.SetDrawingPropertiesFill(sc.Theme, t.Fill, sc.Chart.StyleManager.Style?.Title.FillReference.Color); + Rectangle.SetDrawingPropertiesBorder(sc.Theme, t.Border, sc.Chart.StyleManager.Style?.Title.BorderReference.Color, t.Border.Fill.Style != eFillStyle.NoFill, 0.75); + } + + private void SetAxisTitleRect(ChartRenderer sc, ChartAxisRenderer axis) + { + var margin = 8F; + switch (axis.Axis.AxisPosition) + { + case eAxisPosition.Left: + TextBox.Top = sc.GetPlotAreaTop(); + TextBox.Left = sc.Chart.HasLegend && sc.Chart.Legend.Position == eLegendPosition.Left ? sc.Legend.Rectangle.Right + LeftMargin : margin; + break; + case eAxisPosition.Right: + TextBox.Top = sc.GetPlotAreaTop(); + TextBox.Left = sc.Chart.HasLegend && sc.Chart.Legend.Position == eLegendPosition.Right || sc.Chart.Legend.Position == eLegendPosition.TopRight ? sc.Legend.Rectangle.Left - Rectangle.Width - margin : sc.Bounds.Right - Rectangle.Width - margin; + break; + case eAxisPosition.Bottom: + TextBox.Top = sc.ChartArea.Rectangle.Height - margin - Rectangle.Height; + TextBox.Left = GetHorizontalLeft(sc); + break; + case eAxisPosition.Top: + TextBox.Top = sc.Title != null && sc.Title._title.Layout.HasLayout==false ? sc.Title.Rectangle.Bottom+margin : margin; + TextBox.Left = GetHorizontalLeft(sc); + break; + //case eActualAxisPosition.BottomSecond: + // Rectangle.Top = sc.HorizontalAxis.Rectangle.Bottom; + // Rectangle.Left = GetHorizontalLeft(sc); + // break; + //case eActualAxisPosition.RightSecond: + // Rectangle.Top = sc.GetPlotAreaTop(); + // Rectangle.Left = sc.VerticalAxis.Rectangle.Right; + // break; + } + } + + private double GetHorizontalLeft(ChartRenderer sc) + { + var margin = 8F; + if (sc.HorizontalAxis!=null) + { + if(sc.HorizontalAxis.Axis.Deleted && sc.HorizontalAxis.Title != null && sc.HorizontalAxis.Title._title.Layout.HasLayout==false) + { + return sc.HorizontalAxis.Title.Rectangle.Right; + } + return sc.HorizontalAxis.Rectangle.Right; + } + else + { + return margin; + } + } + + private static string GetDefaultChartTitleText(ChartRenderer sc, ExcelChartTitleStandard t, string defaultText) + { + if (string.IsNullOrEmpty(t.DisplayedText) == false) + { + defaultText = t.DisplayedText; + } + else if (sc.Chart.PlotArea.ChartTypes.Count == 1 && sc.Chart.Series.Count == 1) + { + if (string.IsNullOrEmpty(sc.Chart.Series[0].Header)) + { + var s = sc.Chart.Series[0]; + if (s.NumberLiteralsX != null && s.NumberLiteralsX.Length > 0) + { + defaultText = s.NumberLiteralsX[0].ToString(CultureInfo.InvariantCulture); + } + else if (s.StringLiteralsX != null && s.StringLiteralsX.Length > 0) + { + defaultText = s.StringLiteralsX[0]; + } + else if(s.HeaderAddress!=null) + { + defaultText = s.GetHeaderText(0); + } + } + else + { + defaultText = sc.Chart.Series[0].Header; + } + } + + return defaultText; + } + + internal void InitTextBox(double maxWidth, double maxHeight) + { + TextBox = new DrawingTextBox(_svgChart.Drawing, _svgChart.ChartArea.Rectangle.Bounds, maxWidth, maxHeight); + if (_title.Rotation != 0) + { + TextBox.Rotation = _title.Rotation; + TextBox.Rotation = _title.Rotation; + } + if (_title.TextBody.Paragraphs.Count > 0) + { + TextBox.ImportTextBodyAndParagraphs(_title.TextBody, true, ExcelHorizontalAlignment.Center); + } + else + { + var p = _title.DefaultTextBody.Paragraphs.FirstOrDefault(); + TextBox.ImportParagraph(p, 0, _titleText); + } + + TextBox.LeftMargin = LeftMargin; + TextBox.RightMargin = RightMargin; + TextBox.TopMargin = TopMargin; + TextBox.BottomMargin = BottomMargin; + TextBox.TextBody.VerticalAlignment = TextAnchoringType.Top; + } + + public DrawingTextBox TextBox + { + get; private set; + } + internal override RectRenderItem Rectangle { get => TextBox.Rectangle; set => base.Rectangle = value; } + public override void AppendRenderItems(List renderItems) + { + var p = _title.DefaultTextBody.Paragraphs.FirstOrDefault(); + if (p != null) + { + TextBox.TextBody.FontColorString = "#" + p.DefaultRunProperties.Fill.Color.ToColorString(); + TextBox.Rectangle.SetDrawingPropertiesFill(_svgChart.Theme, _title.Fill, _svgChart.Chart.StyleManager.Style?.Title.FillReference.Color); + TextBox.Rectangle.SetDrawingPropertiesBorder(_svgChart.Theme, _title.Border, _svgChart.Chart.StyleManager.Style?.Title.BorderReference.Color, _title.Border.Fill.Style != eFillStyle.NoFill, 0.75); + } + TextBox.AppendRenderItems(renderItems); + } + + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/BarColumnChartTypeDrawer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/BarColumnChartTypeDrawer.cs new file mode 100644 index 0000000000..50b96224eb --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/BarColumnChartTypeDrawer.cs @@ -0,0 +1,375 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + internal class BarColumnChartTypeDrawer : ChartTypeDrawer + { + List> _catValues, _valValues; + List serieDataLabels = new List(); + List> dataPointsPerSerie = new List>(); + internal override bool SupportsTrendlines => true; + internal override bool SupportsErrorBars => true; + internal BarColumnChartTypeDrawer(ChartRenderer svgChart, ExcelBarChart chartType) : base(svgChart, chartType) + { + _catValues = new List>(); + _valValues = new List>(); + + int serCounter = 0; + + foreach (ExcelBarChartSerie serie in chartType.Series) + { + List valValue,catValue; + valValue = LoadSeriesValues(serie.Series, serie.NumberLiteralsY, serie.StringLiteralsY); + catValue = LoadSeriesValues(serie.XSeries, serie.NumberLiteralsX, serie.StringLiteralsX); + + _catValues.Add(catValue); + _valValues.Add(valValue); + } + + if(chartType.IsTypeStacked()) + { + SumSeries(_valValues); + } + else if (chartType.IsTypePercentStacked()) + { + ExcelChartAxisStandard.CalculateStacked100(_valValues); + } + + CreateTrendlines(chartType, _catValues, _valValues); + CreateErrorBars(chartType, _catValues, _valValues); + } + + internal override void DrawSeries() + { + var isBar = _chartType.IsTypeBar(); + var count = Math.Min(_catValues.Count, _valValues.Count); + for (var i = 0; i < _catValues.Count; i++) + { + var serie = (ExcelBarChartSerie)_chartType.Series[i]; + + var dataPoints = new List(); + + //Add the bar or column. + AddBar((ExcelBarChart)_chartType, serie, _catValues, _valValues, dataPoints, count, i); + + dataPointsPerSerie.Add(dataPoints); + + int serCounter = 0; + + var isColumn = ((ExcelBarChart)_chartType).IsTypeColumn(); + + if (serie.HasDataLabel) + { + var datalabel = new ChartSerieDataLabelRenderer(ChartRenderer, serie.DataLabel, ChartRenderer.Bounds, serie, _catValues[i], _valValues[i], serCounter++); + serieDataLabels.Add(datalabel); + + for (int j = 0; j < dataPoints.Count; j++) + { + //Initialize transforms + Transform basePoint = new Transform(); + Transform endPoint = new Transform(); + basePoint.Parent = dataPoints[j]; + endPoint.Parent = dataPoints[j]; + + if (isColumn == true) + { + var middleRight = dataPoints[j].Left + (dataPoints[j].Width / 2); + + if (chartBaseY <= dataPoints[j].Top) + { + //We are a negative column + // ----- Base-Axis + // |_| Col + basePoint.Position = new Vector2(middleRight, dataPoints[j].Top); + endPoint.Position = new Vector2(middleRight, dataPoints[j].Bottom); + } + else + { + //We are a positive column + // _ + // | | Col + // ----- Base-Axis + basePoint.Position = new Vector2(middleRight, dataPoints[j].Bottom); + endPoint.Position = new Vector2(middleRight, dataPoints[j].Top); + } + + serieDataLabels[i].SetDimensions(j, basePoint, endPoint); + } + else + { + var middleHeight = dataPoints[j].Top + (dataPoints[j].Height / 2); + basePoint.Position = new Vector2(chartBaseY, middleHeight); + if (chartBaseY > dataPoints[j].Left) + { + endPoint.Position = new Vector2(chartBaseY - dataPoints[j].Width, middleHeight); + } + else + { + endPoint.Position = new Vector2(dataPoints[j].Left + dataPoints[j].Width, middleHeight); + } + + serieDataLabels[i].SetDimensions(j, basePoint, endPoint); + } + } + + serCounter++; + } + } + + foreach (var tr in Trendlines) + { + tr.CreateRenderCoordinatesAndDatalabel(); + tr.AppendRenderItems(SeriesRenderItems); + } + + //Add data labels for trendlines after the trendline has been rendered, to ensure they are on top of the line. + foreach (var tr in Trendlines) + { + if (tr.DataLabel != null) + { + tr.DataLabel.AppendRenderItems(ChartAreaRenderItems); + } + } + + foreach (var dataLabel in serieDataLabels) + { + dataLabel.AppendRenderItems(ChartAreaRenderItems); + } + } + + double chartBaseY = double.NaN; + + private void AddBar(ExcelBarChart chartType, ExcelBarChartSerie serie, List> catSeries, List> valSeries, List dataPoints, int seriesCount, int position) + { + GetAxis(chartType, out var yAxis, out var xAxis); + ChartAxisRenderer valAx, catAx; + + var isColumn = chartType.IsTypeColumn(); + + if (isColumn) + { + catAx = xAxis; + valAx = yAxis; + } + else + { + catAx = yAxis; + valAx = xAxis; + } + + var hasErrorBars = serie.HasErrorBars(); + + var catValues = catSeries[position]; + var valValues = valSeries[position]; + + var yWidth = (isColumn ? ChartRenderer.Plotarea.Rectangle.Width : ChartRenderer.Plotarea.Rectangle.Height); + double slotSize; + //if(catAx.IsDateScale) + ////{ + // slotSize = (catAx.Max - catAx.Min) / catAx.MajorUnit + 1; //valValues.Count + //} + //else + //{ + slotSize = catAx.Max - catAx.Min+1; + //} + //var slotSize = (catAx.Max - catAx.Min) / catAx.MajorUnit + 1; //valValues.Count; + //Gapwidth has a default value of 150% See ECMA-376 Part 1 page 4063: + //"286 287 " + var gapWidth = chartType.GapWidth == int.MinValue ? 150 : chartType.GapWidth; + var gapPercent = gapWidth / 100D; // Gap width between bars/columns in percent + var overlapPercent = chartType.Overlap / 100D; // Overlap between bars/columns in percent + var slotWidth = yWidth / slotSize; + var clusterWidth = slotWidth * 100 / (100 + gapWidth); + var step = 1 - overlapPercent; + var barWidth = slotWidth / (1 + (seriesCount - 1) * step + gapPercent); + var halfGap = (barWidth * gapPercent) / 2; + + if (catAx.Axis.Crosses == eCrosses.AutoZero) + { + chartBaseY = valAx.GetPositionInPlotarea(valAx.Min <= 0 ? 0D : valAx.Min, true); + } + else if (catAx.Axis.Crosses == eCrosses.Min) + { + chartBaseY = valAx.GetPositionInPlotarea(valAx.Min, true); + } + else + { + chartBaseY = valAx.GetPositionInPlotarea(valAx.Max, true); + } + + var isStacked = chartType.IsTypeStacked(); + var isStacked100 = chartType.IsTypePercentStacked(); + for (var i = 0; i < valValues.Count; i++) + { + double x; + if (catValues == null || catAx.Axis.AxisType == eAxisType.Cat) + { + if (isColumn) + { + x = (double)i; + } + else + { + x = valValues.Count - i - 1; + } + } + else + { + if (isColumn) + { + x = ConvertUtil.GetValueDouble(catValues[i], false, true); + } + else + { + var ix = valValues.Count - i - 1; + if (ix < catValues.Count) + { + x = ConvertUtil.GetValueDouble(catValues[ix], false, true); + } + else + { + x = 0; + } + } + } + + var y = ConvertUtil.GetValueDouble(valValues[i], false, true); + + var rect = new RectRenderItem(ChartRenderer.Plotarea.Rectangle.Bounds); + var yPos = valAx.GetPositionInPlotarea(y); + double xPos; + if (isColumn) + { + xPos = catAx.GetPositionInPlotarea(x, true) + halfGap + position * barWidth * step; + rect.Left = xPos; + rect.Width = barWidth; + } + else + { + xPos = catAx.GetPositionInPlotarea(x, true) + halfGap + (seriesCount - position - 1) * barWidth * step; + rect.Top = xPos; + rect.Height = barWidth; + } + + if (position > 0 && (isStacked || isStacked100)) + { + //Stacked + var pYValues = valSeries[position - 1]; + var pAxisEnd = ConvertUtil.GetValueDouble(pYValues[i]); + var yPrevPos = yAxis.GetPositionInPlotarea(pAxisEnd, false); + if (isColumn) + { + if (y < 0) + { + rect.Top = yPrevPos; + rect.Height = yPos - yPrevPos; + } + else + { + rect.Top = yPos; + rect.Height = yPrevPos - yPos; + } + } + else + { + if (y < 0) + { + rect.Left = yPrevPos; + rect.Width = yPos - yPrevPos; + } + else + { + rect.Left = yPos; + rect.Width = yPrevPos - yPos; + } + } + } + else + { + if (isColumn) + { + if (y < 0) + { + rect.Top = chartBaseY; + rect.Height = yPos - chartBaseY; + } + else + { + rect.Top = yPos; + rect.Height = chartBaseY - yPos; + } + } + else + { + if (y < 0) + { + rect.Left = yPos; + rect.Width = chartBaseY - yPos; + } + else + { + rect.Left = chartBaseY; + rect.Width = yPos - chartBaseY; + } + } + } + + rect.SetDrawingPropertiesFill(ChartRenderer.Theme, serie.Fill, chartType.StyleManager.Style?.SeriesAxis.FillReference.Color, false); + rect.SetDrawingPropertiesBorder(ChartRenderer.Theme, serie.Border, chartType.StyleManager.Style?.SeriesAxis.BorderReference.Color, true, 1.5, false); + rect.SetDrawingPropertiesEffects(ChartRenderer.Theme, serie.Effect); + + dataPoints.Add(rect.Bounds); + + SeriesRenderItems.Add(rect); + + if (hasErrorBars) + { + if(isColumn) + { + //x += barWidth / 2; + xPos += rect.Width / 2; + } + else + { + //y += barWidth / 2; + xPos += rect.Height / 2; + } + SeriesRenderItems.AddRange(ErrorBars.GetErrorBarRenderItem(i, catAx, valAx, x, y, xPos, yPos)); + } + } + } + private void GetAxis(ExcelBarChart chartType, out ChartAxisRenderer yAxis, out ChartAxisRenderer xAxis) + { + if (chartType.UseSecondaryAxis) + { + yAxis = ChartRenderer.SecondVerticalAxis; + xAxis = ChartRenderer.SecondHorizontalAxis; + if (xAxis.Axis.Deleted && xAxis.Values == null) + { + xAxis = ChartRenderer.HorizontalAxis; + } + } + else + { + yAxis = ChartRenderer.VerticalAxis; + xAxis = ChartRenderer.HorizontalAxis; + } + } + + public override void AppendRenderItems(List renderItems) + { + renderItems.AddRange(ChartAreaRenderItems); + SeriesRenderItems.ForEach(x => ChartRenderer.Plotarea.Group.AddChildItem(x)); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartErrorBarRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartErrorBarRenderer.cs new file mode 100644 index 0000000000..cc1d72b285 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartErrorBarRenderer.cs @@ -0,0 +1,241 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Tables.Cmap; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using static OfficeOpenXml.ExcelErrorValue; + +namespace OfficeOpenXml.Drawing.Renderer.Chart.ChartTypeDrawers +{ + internal class ChartErrorBarRenderer : ChartDrawingObject + { + internal ExcelChartErrorBars _errorbars; + private double[] _ySerie; + private List _xSerie; + private ExcelChart _chartType; + + internal List Values { get; set; } = new List(); + public ChartErrorBarRenderer(ChartRenderer svgChart, ExcelChartErrorBars errorbars, List xSerie, List ySerie, ExcelChart chartType, int seriePos) : base(svgChart) + { + _chartType = chartType; + _errorbars = errorbars; + _xSerie = GetXSerie(xSerie); + _ySerie = ySerie.Select(y => ConvertUtil.GetValueDouble(y)).ToArray(); + //_useSecondaryAxis = chartType.UseSecondaryAxis; + //_serieCount = _chartType.Series.Count; + //_seriePos = seriePos; + int n = xSerie.Count; + + switch (errorbars.ValueType) + { + case eErrorValueType.StandardError: + case eErrorValueType.StandardDeviation: + if (n > 1) + { + double avg = _ySerie.Average(); + double sumSquaredDeviations = _ySerie.Sum(v => (v - avg) * (v - avg)); + double sampleStdDev = Math.Sqrt(sumSquaredDeviations / (n - 1)); // sample std dev (n-1) + for (int i=0;i < _xSerie.Count;i++) + { + if (i >= _ySerie.Length) break; + + if(errorbars.ValueType == eErrorValueType.StandardError) + { + double se = sampleStdDev / Math.Sqrt(n); + double y = _ySerie[i]; + Values.Add(new double[] { y - se, y, y + se }); + } + else + { + var mult = errorbars.Value ?? 1D; + Values.Add(new double[] { avg - sampleStdDev, avg, avg + sampleStdDev }); + } + } + } + break; + case eErrorValueType.Percentage: + var percent = (errorbars.Value ?? 0D) / 100D; + for (int i = 0; i < _xSerie.Count; i++) + { + double y = _ySerie[i]; + Values.Add(new double[] { y * (1 - percent), y, y * (1 + percent) }); + } + break; + case eErrorValueType.FixedValue: + var fixedValue = errorbars.Value ?? 0D; + for (int i = 0; i < _xSerie.Count; i++) + { + double y = _ySerie[i]; + Values.Add(new double[] { y - fixedValue, y, y + fixedValue }); + } + + break; + case eErrorValueType.Custom: + var minusList = errorbars.Minus.GetValuesList(_chartType.WorkSheet.Workbook); + var plusList = errorbars.Plus.GetValuesList(_chartType.WorkSheet.Workbook); + for (int i = 0; i < _xSerie.Count; i++) + { + double y = _ySerie[i]; + double minus = GetCustomValue(minusList, i); + double plus = GetCustomValue(plusList, i); + Values.Add(new double[] { y - minus, y, y + plus }); + } + + break; + } + } + public double GetCustomValue(List l, int i) + { + if(l.Count==1) + { + return l[0]; + } + else if(i GetErrorBarRenderItem(int index, ChartAxisRenderer xAxis, ChartAxisRenderer yAxis, double x, double y, double xPos, double yPos) + { + //var path = new PathRenderItem(ChartRenderer.Bounds); + var l = new List(); + double topValue=0, bottomValue=0; + if (_errorbars.BarType == eErrorBarType.Plus || _errorbars.BarType == eErrorBarType.Both) + { + topValue = Values[index][2]; + } + if(_errorbars.BarType == eErrorBarType.Minus || _errorbars.BarType == eErrorBarType.Both) + { + bottomValue = Values[index][0]; + } + + //if (_errorbars.Direction == eErrorBarDirection.X ) + if(_chartType.IsTypeBar()) + { + var rightPos = yAxis.GetPositionInPlotarea(topValue); + var centerPos = yAxis.GetPositionInPlotarea(Values[index][1]); + var leftPos = yAxis.GetPositionInPlotarea(bottomValue); + + //Bottom line + //path.Commands.Add(new PathCommands(PathCommandType.Move, leftPos, yPos, centerPos, yPos)); + var bl = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = leftPos, + Y1 = xPos, + X2 = centerPos, + Y2 = xPos + }; + + //Top line + //path.Commands.Add(new PathCommands(PathCommandType.Move, centerPos, yPos, rightPos, yPos)); + var tl = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = centerPos, + Y1 = xPos, + X2 = rightPos, + Y2 = xPos + }; + l.Add(bl); + l.Add(tl); + if (_errorbars.NoEndCap == false) + { + //Bottom cap + //path.Commands.Add(new PathCommands(PathCommandType.Move, leftPos, yPos - 3, leftPos, yPos + 3)); + var bc = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = leftPos, + Y1 = xPos - 3, + X2 = leftPos, + Y2 = xPos + 3 + }; + //Top cap + //path.Commands.Add(new PathCommands(PathCommandType.Move, rightPos, yPos - 3, rightPos, yPos + 3)); + var tc = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = rightPos, + Y1 = xPos - 3, + X2 = rightPos, + Y2 = xPos + 3 + }; + l.Add(bc); + l.Add(tc); + } + } + else + { + var bottomPos = xAxis.GetPositionInPlotarea(bottomValue); + var centerPos = xAxis.GetPositionInPlotarea(Values[index][1]); + var topPos = xAxis.GetPositionInPlotarea(topValue); + + //Bottom line + //path.Commands.Add(new PathCommands(PathCommandType.Move, xPos, bottomPos, xPos, centerPos)); + var bl = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = xPos, + Y1 = bottomPos, + X2 = xPos, + Y2 = centerPos + }; + //Top line + //path.Commands.Add(new PathCommands(PathCommandType.Move, xPos, topPos, xPos, centerPos)); + var tl = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = xPos, + Y1 = topPos, + X2 = xPos, + Y2 = centerPos + }; + l.Add(bl); + l.Add(tl); + if (_errorbars.NoEndCap == false) + { + //Bottom cap + //path.Commands.Add(new PathCommands(PathCommandType.Move, xPos-3, bottomPos, xPos+3, bottomPos)); + var bc = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = xPos - 3, + Y1 = bottomPos, + X2 = xPos + 3, + Y2 = bottomPos + }; + + //Top cap + //path.Commands.Add(new PathCommands(PathCommandType.Move, xPos - 3, topPos, xPos + 3, topPos)); + var tc = new LineRenderItem(ChartRenderer.Bounds) + { + X1 = xPos - 3, + Y1 = topPos, + X2 = xPos + 3, + Y2 = topPos + }; + l.Add(bc); + l.Add(tc); + } + } + foreach (var ri in l) + { + if (_errorbars.Border.LineElement == null) + { + ri.SetDrawingPropertiesBorder(ChartRenderer.Theme, ChartRenderer.Chart.StyleManager.Style?.ErrorBar.Border, ChartRenderer.Chart.StyleManager.Style?.ErrorBar.BorderReference.Color, true, 0.75); + } + else + { + ri.SetDrawingPropertiesBorder(ChartRenderer.Theme, _errorbars.Border, ChartRenderer.Chart.StyleManager.Style?.ErrorBar.BorderReference.Color, _errorbars.Border.Fill.Style != eFillStyle.NoFill, 0.75); + } + ri.SetDrawingPropertiesEffects(ChartRenderer.Theme, _errorbars.Effect); + } + return l; + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartTypeDrawer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartTypeDrawer.cs new file mode 100644 index 0000000000..5b164ad296 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/ChartTypeDrawer.cs @@ -0,0 +1,229 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.Svg.Chart.ChartTypeDrawers; +using EPPlus.Export.ImageRenderer.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Chart.ChartEx; +using OfficeOpenXml.Drawing.Renderer.Chart.ChartTypeDrawers; +using OfficeOpenXml.ExternalReferences; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Finance; +using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + internal abstract class ChartTypeDrawer : ChartDrawingObject + { + internal protected ExcelChart _chartType; + internal List Trendlines { get; } = new List(); + internal ChartErrorBarRenderer ErrorBars { get; private set; } + internal virtual bool SupportsTrendlines { get { return false; } } + internal virtual bool SupportsErrorBars { get { return false; } } + internal virtual bool SupportsUpDownBars { get { return false; } } + internal virtual bool SupportsDataTable { get { return false; } } + internal ChartTypeDrawer(ChartRenderer svgChart, ExcelChart chartType) : base(svgChart) + { + _chartType = chartType; + //Avoid null-refs + Rectangle = new RectRenderItem(svgChart.Bounds); + } + internal abstract void DrawSeries(); + protected List LoadSeriesValues(string serieAddressInput, double[] numLiterals, string[] strLiterals) + { + string serieAddress = serieAddressInput; + + //Some addresses are split and within parenthesis + if (serieAddressInput.StartsWith("(")) + { + serieAddress = serieAddressInput.Trim('(', ')'); + } + + List values = new List(); + if (numLiterals != null) + { + values.AddRange(numLiterals.Select(x => (object)x)); + } + else if (strLiterals != null) + { + values.AddRange(strLiterals.Select(x => (object)x)); + } + else + { + if (string.IsNullOrEmpty(serieAddress)) + { + return null; + } + var address = new ExcelAddressBase(serieAddress); + + if (address.Addresses != null && address.Addresses.Count > 1) + { + foreach (var splitAddress in address.Addresses) + { + FillValuesFromAddress(splitAddress, ref values); + } + } + else + { + FillValuesFromAddress(address, ref values); + } + } + return values; + } + + protected void FillValuesFromAddress(ExcelAddressBase address, ref List values) + { + if (address.IsExternal) + { + var wb = Chart.WorkSheet.Workbook; + var extWb = wb.ExternalLinks[address.ExternalReferenceIndex - 1] as ExcelExternalWorkbook; + if (extWb != null) + { + var wsName = address.WorkSheetName; + if (extWb.Package == null) + { + var extWs = extWb.CachedWorksheets[wsName]; + FillExternalValues(extWs, address, ref values); + } + else + { + var ws = extWb.Package.Workbook.Worksheets[wsName]; + FillInternalValues(ws, address, ref values); + } + } + } + else + { + var wsName = address.WorkSheetName; + + if (string.IsNullOrEmpty(wsName)) + { + wsName = Chart.WorkSheet.Name; + } + + var ws = Chart.WorkSheet.Workbook.Worksheets[wsName]; + FillInternalValues(ws, address, ref values); + } + } + + protected void FillExternalValues(ExcelExternalWorksheet extWs, ExcelAddressBase address, ref List values) + { + if (extWs != null) + { + for (int r = address.Start.Row; r <= address.End.Row; r++) + { + for (int c = address.Start.Column; c <= address.End.Column; c++) + { + values.Add(extWs.CellValues[r, c].Value); + } + } + } + } + + private void FillInternalValues(ExcelWorksheet ws, ExcelAddressBase address, ref List values) + { + + if (ws != null) + { + for (int r = address.Start.Row; r <= address.End.Row; r++) + { + for (int c = address.Start.Column; c <= address.End.Column; c++) + { + values.Add(ws.Cells[r, c].Value); + } + } + } + } + + public List SeriesRenderItems { get; } = new List(); + public List ChartAreaRenderItems { get; } = new List(); + internal static List Create(ChartRenderer svgChart) + { + var drawers = new List(); + foreach (var ct in svgChart.Chart.PlotArea.ChartTypes) + { + switch (ct.ChartType) + { + case eChartType.Line: + case eChartType.LineMarkers: + case eChartType.LineStacked: + case eChartType.LineStacked100: + case eChartType.LineMarkersStacked: + case eChartType.LineMarkersStacked100: + drawers.Add(new LineChartTypeDrawer(svgChart, (ExcelLineChart)ct)); + break; + case eChartType.ColumnClustered: + case eChartType.ColumnStacked: + case eChartType.ColumnStacked100: + case eChartType.BarClustered: + case eChartType.BarStacked: + case eChartType.BarStacked100: + drawers.Add(new BarColumnChartTypeDrawer(svgChart, (ExcelBarChart)ct)); + break; + case eChartType.Pie: + case eChartType.PieExploded: + drawers.Add(new PieChartTypeDrawer(svgChart, (ExcelPieChart)ct)); + break; + default: + throw new NotImplementedException($"No Svg support for Chart type {ct} is implemented."); + } + } + return drawers; + } + internal void SumSeries(List> series) + { + for (var i = 1; i < series.Count; i++) + { + for (var j = 0; j < series[i].Count; j++) + { + series[i][j] = ConvertUtil.GetValueDouble(series[i][j]) + ConvertUtil.GetValueDouble(series[i - 1][j]); + } + } + } + protected void CreateTrendlines(ExcelChart chartType, List> xValues, List> yValues) + { + var serieIndex = 0; + foreach (ExcelChartSerie serie in chartType.Series) + { + if (serie.TrendLines.Count > 0) + { + var xSerie = xValues[serieIndex]; + var ySerie = yValues[serieIndex]; + foreach (var trendline in serie.TrendLines) + { + var tr = new ChartTrendlineRenderer(ChartRenderer, trendline, xSerie, ySerie, _chartType, serieIndex); + Trendlines.Add(tr); + } + } + serieIndex++; + } + } + protected void CreateErrorBars(ExcelChart chartType, List> xValues, List> yValues) + { + if (!(chartType.IsTypeLine() || chartType.IsTypeColumn() || chartType.IsTypeBar())) return; + + var serieIndex = 0; + foreach (ExcelChartSerieWithErrorBars serie in chartType.Series) + { + if (serie.HasErrorBars()) + { + var xSerie = xValues[serieIndex]; + var ySerie = yValues[serieIndex]; + ErrorBars = new ChartErrorBarRenderer(ChartRenderer, serie.ErrorBars, xSerie, ySerie, _chartType, serieIndex); + } + serieIndex++; + } + } + + internal bool IsOnAxis(ExcelChartAxisStandard ax) + { + return _chartType.YAxis==ax || _chartType.XAxis==ax; + } + } + +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs new file mode 100644 index 0000000000..1c368a47d7 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs @@ -0,0 +1,231 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.DigitalSignatures; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Renderer.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + internal class LineChartTypeDrawer : ChartTypeDrawer + { + List> _xValues, _yValues; + + List serieDataLabels = new List(); + List> dataPointsPerSerie = new List>(); + internal override bool SupportsTrendlines => true; + internal override bool SupportsErrorBars => true; + internal LineChartTypeDrawer(ChartRenderer svgChart, ExcelLineChart chartType) : base(svgChart, chartType) + { + var isStacked = chartType.IsTypeStacked(); + var isPercentStacked = chartType.IsTypePercentStacked(); + int serCounter = 0; + _xValues = new List>(); + _yValues = new List>(); + foreach (ExcelLineChartSerie serie in chartType.Series) + { + var yValue = LoadSeriesValues(serie.Series, serie.NumberLiteralsY, serie.StringLiteralsY); + var xValue = LoadSeriesValues(serie.XSeries, serie.NumberLiteralsX, serie.StringLiteralsX); + if(xValue==null) + { + //No x-axis. Create serie from 1..y-items. + xValue = yValue.Select((x, index) => (object)(double)(index + 1)).ToList(); + } + _xValues.Add(xValue); + _yValues.Add(yValue); + + serCounter++; + } + + if (chartType.IsTypeStacked()) + { + SumSeries(_yValues); + } + else if (chartType.IsTypePercentStacked()) + { + ExcelChartAxisStandard.CalculateStacked100(_yValues); + } + + CreateTrendlines(chartType, _xValues, _yValues); + CreateErrorBars(chartType, _xValues, _yValues); + } + internal override void DrawSeries() + { + var lct = (ExcelLineChart)_chartType; + for (var i = 0; i < _xValues.Count; i++) + { + var xSerie = _xValues[i]; + var ySerie = _yValues[i]; + var serie = lct.Series[i]; + + if (serie.HasDataLabel) + { + var datalabel = new ChartSerieDataLabelRenderer(ChartRenderer, serie.DataLabel, ChartRenderer.Bounds, serie, xSerie, ySerie, i); + serieDataLabels.Add(datalabel); + } + + + var dataPoints = new List(); + AddLine(_chartType, serie, xSerie, ySerie, dataPoints); + + dataPointsPerSerie.Add(dataPoints); + + if (serie.HasDataLabel) + { + for (int j = 0; j < dataPoints.Count; j++) + { + serieDataLabels[i].SetParentPoint(dataPoints[j], j); + } + } + } + + + //Append Trendline render items. + foreach (var tr in Trendlines) + { + tr.CreateRenderCoordinatesAndDatalabel(); + tr.AppendRenderItems(SeriesRenderItems); + } + + //Datalabels use the chart area as parent as they can be positioned on the entire chart. + + //Add data labels for trendlines after the trendline has been rendered, to ensure they are on top of the line. + foreach (var tr in Trendlines) + { + if (tr.DataLabel != null) + { + tr.DataLabel.AppendRenderItems(ChartAreaRenderItems); + } + } + + //Date series labels + foreach (var dataLabel in serieDataLabels) + { + dataLabel.AppendRenderItems(ChartAreaRenderItems); + } + } + private void SumSeries(List> series) + { + for(var i=1;i < series.Count;i++) + { + for(var j=0;j < series[i].Count;j++) + { + series[i][j] = ConvertUtil.GetValueDouble(series[i][j]) + ConvertUtil.GetValueDouble(series[i-1][j]); + } + } + } + private void AddLine(ExcelChart chartType, ExcelLineChartSerie serie, List xValues, List yValues, List dataPoints) + { + ChartAxisRenderer yAxis, xAxis; + if (chartType.UseSecondaryAxis) + { + yAxis = ChartRenderer.SecondVerticalAxis; + xAxis = ChartRenderer.SecondHorizontalAxis; + if(xAxis.Axis.Deleted && xAxis.Values==null) + { + xAxis = ChartRenderer.HorizontalAxis; + } + } + else + { + yAxis = ChartRenderer.VerticalAxis; + xAxis = ChartRenderer.HorizontalAxis; + } + var linePath = new PathRenderItem(ChartRenderer.Plotarea.Rectangle.Bounds); + var coords = new List(); + var markerItems = new List(); + var errorBars = new List(); + + var hasMarker = serie.HasMarker() && serie.Marker.Style != eMarkerStyle.None; + var hasErrorBars = serie.HasErrorBars(); + for (var i = 0; i < yValues.Count; i++) + { + double x; + if (xValues == null || xAxis.Axis.AxisType==eAxisType.Cat) + { + x = (double)i; + } + else + { + x = ConvertUtil.GetValueDouble(xValues[i], false, true); + } + + var y = ConvertUtil.GetValueDouble(yValues[i], false, true); + var xPos = xAxis.GetPositionInPlotarea(x); + var yPos = yAxis.GetPositionInPlotarea(y); + + BoundingBox pt = null; + + if (double.IsNaN(yPos) == false) + { + coords.Add(xPos); + coords.Add(yPos); + + //Log point within chart coordinate system + pt = new BoundingBox(xPos, yPos, 0, 0); + pt.Parent = ChartRenderer.Plotarea.Rectangle.Bounds; + } + if(hasErrorBars) + { + errorBars.AddRange(ErrorBars.GetErrorBarRenderItem(i, xAxis, yAxis, x, y, xPos, yPos)); + } + if (hasMarker) + { + float mx = (float)xPos; + float my = (float)yPos; + var ls = LineMarkerHelper.GetMarkerItem(ChartRenderer, serie, mx, my, false); + if ((serie.Marker.Style == eMarkerStyle.Plus || serie.Marker.Style == eMarkerStyle.X || serie.Marker.Style == eMarkerStyle.Star) && + serie.Marker.Fill.IsEmpty == false) + { + markerItems.Add(LineMarkerHelper.GetMarkerBackground(ChartRenderer, serie, mx, my, false)); + } + markerItems.Add(ls); + + if (pt != null) + { + pt.Width = ls.Bounds.Width; + pt.Height = ls.Bounds.Height; + dataPoints.Add(pt); + } + } + else + { + + if (pt != null) + { + //Default values in excel + pt.Width = 5; + pt.Height = 5; + dataPoints.Add(pt); + } + } + } + + linePath.Commands.Add(new PathCommands(PathCommandType.Move, coords.ToArray())); + linePath.SetDrawingPropertiesBorder(ChartRenderer.Theme, serie.Border, chartType.StyleManager.Style?.SeriesLine.BorderReference.Color, true); + linePath.SetDrawingPropertiesEffects(ChartRenderer.Theme, serie.Effect); + linePath.FillColor = "none"; //No fill for line + linePath.StrokeMiterLimit = 4; //A much higher value of the miter limit, might cause the "spike" to get beyond the data point on the vertical scale.. + linePath.LineJoin = LineJoin.Round; + SeriesRenderItems.Add(linePath); + SeriesRenderItems.AddRange(markerItems); + SeriesRenderItems.AddRange(errorBars); + } + + + public override void AppendRenderItems(List renderItems) + { + renderItems.AddRange(ChartAreaRenderItems); + SeriesRenderItems.ForEach(x=> ChartRenderer.Plotarea.Group.AddChildItem(x)); + } + } + +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/PieChartTypeDrawer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/PieChartTypeDrawer.cs new file mode 100644 index 0000000000..9c4ec5975e --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/PieChartTypeDrawer.cs @@ -0,0 +1,279 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Export.ImageRenderer.Utils; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.DigitalSignatures; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Utils.Drawing; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart.ChartTypeDrawers +{ + internal class PieChartTypeDrawer : ChartTypeDrawer + { + List serieDataLabels = new List(); + List catValues = new List(); + List valValues = new List(); + List _serieValuesAsDoubles = new List(); + List> dataPointsPerSerie = new List>(); + double _totalOfSerieValues = 0; + + List Slices = new List(); + + GroupRenderItem _groupItem; + + double _startDegrees = -90d; + int _pieExplosionPercent = 0; + + double _sliceScaleFactor = 1.0; + int _serCounter = 0; + + /// + /// Radius in points + /// + double _radius; + + Point _circleCenter; + + public PieChartTypeDrawer(ChartRenderer chart, ExcelPieChart chartType) : base(chart, chartType) + { + //Moved to draw series + } + + void RenderDebugEllipse() + { + var circ = new EllipseRenderItem(ChartRenderer.Plotarea.Rectangle.Bounds); + + circ.Bounds.Left = _circleCenter.Left; + circ.Bounds.Top = _circleCenter.Top; + + circ.Rx = _radius; + circ.Ry = _radius; + + circ.Cx = _circleCenter.Left; + circ.Cy = _circleCenter.Top; + + circ.FillColor = "transparent"; + circ.FillOpacity = 0.3d; + circ.BorderColor = "purple"; + circ.BorderWidth = 10; + + _groupItem.RenderItems.Add(circ); + } + + Coordinate CalculateLocalPointOnCircle(double degrees) + { + var angleRadians = MConverter.DegreesToRadians(degrees); + + var xPoint = _circleCenter.Left + (_radius * Math.Cos(angleRadians)); + var yPoint = _circleCenter.Top + (_radius * Math.Sin(angleRadians)); + + return new Coordinate(xPoint, yPoint); + } + + void InitializeSlices() + { + //The angle of the previous slice + //(or the 90 degree offset in the first slice) + var prevDegrees = _startDegrees; + + for (int i = 0; i < valValues.Count; i++) + { //Calculate how many percent of the pie this slice is + var valPercent = _serieValuesAsDoubles[i] / _totalOfSerieValues; + //Create and add slice + PieSliceRenderItem slice = new PieSliceRenderItem(ChartRenderer, _groupItem.Bounds, _circleCenter, _radius, valPercent, prevDegrees); + Slices.Add(slice); + + //Next slice will need to be calculated starting from the degrees of this slice + prevDegrees = slice.Degrees + prevDegrees; + } + } + + void CalculateLocalCenterAndRadius() + { + _circleCenter = new Point(); + _circleCenter.Parent = _groupItem.TranslationOffset; + _circleCenter.Left = ChartRenderer.Plotarea.Rectangle.Bounds.Width / 2; + _circleCenter.Top = ChartRenderer.Plotarea.Rectangle.Bounds.Height / 2; + + _groupItem.RotationPoint = _circleCenter; + + _radius = Math.Min(_circleCenter.Left, _circleCenter.Top); + } + + void LoadSeriesValues(ExcelPieChart chartType) + { + //Load series values + foreach (ExcelPieChartSerie serie in chartType.Series) + { + //Excel allows further series on a pie chart but ignores them for visualization + if(_serCounter == 0) + { + + valValues = LoadSeriesValues(serie.Series, serie.NumberLiteralsY, serie.StringLiteralsY); + catValues = LoadSeriesValues(serie.XSeries, serie.NumberLiteralsX, serie.StringLiteralsX); + + //Pie explosion + _pieExplosionPercent = serie.Explosion == int.MinValue ? 0 : serie.Explosion; + + //Add Datalabel + if (serie.HasDataLabel) + { + var datalabel = new ChartSerieDataLabelRenderer(ChartRenderer, serie.DataLabel, ChartRenderer.Bounds, serie, catValues, valValues, _serCounter); + serieDataLabels.Add(datalabel); + } + } + + _serCounter++; + } + + ConvertSerieValuesToDoubles(); + } + + void ConvertSerieValuesToDoubles() + { + for (int i = 0; i < valValues.Count; i++) + { + var origValue = valValues[i]; + var dValue = ConvertUtil.GetValueDouble(origValue, false, true); + if (double.IsNaN(dValue)) + { + //Ignore values that are NAN. Possibly we should throw here but Excel simply seems to skip it. + continue; + } + _serieValuesAsDoubles.Add(dValue); + _totalOfSerieValues += _serieValuesAsDoubles[i]; + } + } + + private void UpdateSlice(ExcelPieChart chartType, ExcelPieChartSerie serie, int seriesCount, int position) + { + var dataPoint = serie.DataPoints[position]; + + Slices[position].ImportPathData( + ChartRenderer.Plotarea.Rectangle.Bounds, ChartRenderer.Bounds, + _sliceScaleFactor, dataPoint.Explosion, _pieExplosionPercent, position); + + Slices[position].ImportStlyeInfo(dataPoint, chartType); + Slices[position].AppendGroupItem(_groupItem); + } + + internal override void DrawSeries() + { + _groupItem = new GroupRenderItem(ChartRenderer.Plotarea.Group.Bounds); + + Rectangle.Bounds.Name = "ChartDrawer"; + _groupItem.Bounds.Name = "OuterGroupChartDrawer"; + + var chartType = (ExcelPieChart)_chartType; + + //Read and set Starting angle offset as a rotation on the container + //This way no rotation messes with the other calculations + var angleOffset = double.IsNaN(chartType.FirstSliceAngle) ? 0 : chartType.FirstSliceAngle; + _groupItem.Rotation = angleOffset; + + LoadSeriesValues(chartType); + CalculateLocalCenterAndRadius(); + if (serieDataLabels.Count > 0) + { + serieDataLabels[0].rotation = angleOffset; + serieDataLabels[0].rotationPoint = _groupItem.RotationPoint; + } + + InitializeSlices(); + + //How much to scale each slice due to pie explosion + //Essentially we start at 100% (100/100) + //And then scale down by adding the pie explosionPercent (0-400) + // 100/200 -> 0.5, 100/400 -> 0.2 etc. + _sliceScaleFactor = 100d / (_pieExplosionPercent + 100d); + + if (_sliceScaleFactor != 1) + { + //Small adjustment. Unsure why but closer results + //Could be Excel pixel rounding or 2px border buffer + _sliceScaleFactor += 0.02d; + } + + int dataPointCount = 0; + if (catValues != null) + { + if (valValues != null) + { + dataPointCount = Math.Max(catValues.Count, valValues.Count); + } + else + { + dataPointCount = catValues.Count; + } + } + else + { + if (valValues != null) + { + dataPointCount = valValues.Count; + } + } + + for (int i = 0; i < chartType.Series.Count; i++) + { + var serie = (ExcelPieChartSerie)chartType.Series[i]; + + List DataLabelGlobalOriginPoints = new(); + List VectorsCenterToMidPointPerSlice = new(); + + //Excel ignores series beyond the first for pie chart visualization + if (i == 0) + { + for (var j = 0; j < Slices.Count; j++) + { + //Update the initialized slice with path, style and group data + UpdateSlice(chartType, serie, dataPointCount, j); + + if (serie.HasDataLabel) + { + var innerGroup = Slices[j].GetInnerGroupWithTransformOriginTranslated(); + //Get the global position of the inner items (innerGroup the parent of itemGroup has already had its position set correctly) + var dlblBounds = new BoundingBox(innerGroup.LocalPosition.X, innerGroup.LocalPosition.Y, Rectangle.Bounds.Width, Rectangle.Bounds.Height); + + var ctrToMid = Slices[j].GetWholeVectorCenterToMid(); + var startPt = new Transform(); + startPt.Parent = innerGroup.Parent; + startPt.Position = innerGroup.Position + (ctrToMid * -1); + + serieDataLabels[i].SetDimensions(j, startPt, innerGroup); + } + } + } + } + + //RenderDebugEllipse(); + + ChartAreaRenderItems.Add(_groupItem); + //Series Labels + foreach (var dataLabel in serieDataLabels) + { + dataLabel.AppendRenderItems(SeriesRenderItems); + } + } + + public override void AppendRenderItems(List renderItems) + { + ChartRenderer.Plotarea.Group.AddChildItem(_groupItem); + if(SeriesRenderItems != null && SeriesRenderItems.Count > 0) + { + ChartRenderer.RenderItems.Add(SeriesRenderItems[0]); + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/Trendlines/ChartTrendlineRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/Trendlines/ChartTrendlineRenderer.cs new file mode 100644 index 0000000000..4e11687cd4 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/Trendlines/ChartTrendlineRenderer.cs @@ -0,0 +1,786 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 22/10/2022 EPPlus Software AB EPPlus v6 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.Textbox; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Statistical; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + internal class ChartTrendlineRenderer : ChartDrawingObject + { + private ExcelChartTrendline _trendline; + private double[] _ySerie; + private List _xSerie; + private ExcelChart _chartType; + private bool _useSecondaryAxis; + private int _serieCount, _seriePos; + public ChartTrendlineRenderer(ChartRenderer svgChart, ExcelChartTrendline trendline, List xSerie, List ySerie, ExcelChart chartType, int seriePos) : base(svgChart) + { + _chartType = chartType; + _trendline = trendline; + _xSerie = GetXSerie(xSerie); + _ySerie = ySerie.Select(y => ConvertUtil.GetValueDouble(y)).ToArray(); + _useSecondaryAxis = chartType.UseSecondaryAxis; + _serieCount = _chartType.Series.Count; + _seriePos = seriePos; + double m, b; + switch (trendline.Type) + { + case eTrendLine.Linear: + CalculateLinear(); + Coordinates.Add(new Coordinate(0, GetLinearValueAtPosition(1))); + Coordinates.Add(new Coordinate(_xSerie.Count-1, GetLinearValueAtPosition(_xSerie.Count))); + break; + case eTrendLine.Exponential: + CalculateExponential(); + m = Coefficients[0]; + b = Coefficients[1]; + CreateCoordinates(x => b * Math.Exp(m * x)); + break; + case eTrendLine.Logarithmic: + CalculateLogarithmic(); + m = Coefficients[0]; + b = Coefficients[1]; + CreateCoordinates(x => m * Math.Log(x) + b); + break; + case eTrendLine.Polynomial: + CalculatePolynomial(); + CreateCoordinates(x=> PredictPolynomial(x)); + break; + case eTrendLine.Power: + CalculatePower(); + + m = Coefficients[0]; + b = Coefficients[1]; + CreateCoordinates(x => b * Math.Pow(x, m)); + break; + case eTrendLine.MovingAverage: + CalculateMoveingAverage(); + + for (int i = ((int)_trendline.Period) - 1; i < _xSerie.Count; i++) + { + var x = i; + var y = GetMonthlyAverageAtPosition(i); + + Coordinates.Add(new Coordinate(x, y)); + } + + + break; + default: + //Should not happen unless new trendline types arrive. + throw new NotImplementedException("Trendline type not implemented."); + } + } + + private void CreateDatalabel() + { + if(_trendline.DisplayEquation==false && _trendline.DisplayRSquaredValue==false) + { + return; + } + //Display the label for the trendline with equation and R² value. + var lbl = _trendline.Label; + var coord = RenderCoordinates; + var x = ChartRenderer.Plotarea.Group.Left + coord[coord.Length - 2]; + var y = ChartRenderer.Plotarea.Group.Top + coord[coord.Length - 1]; + double width = 0, height = 0; + + if (_trendline.Label.Layout.HasLayout) + { + var mlRect = GetRectFromManualLayout(ChartRenderer, _trendline.Label.Layout); + x += mlRect.Left; + y += mlRect.Top; + if (lbl.Layout.ManualLayout.Width.HasValue && lbl.Layout.ManualLayout.Height.HasValue) + { + width = mlRect.Width; + height = mlRect.Height; + } + } + + if (width > 0 && height > 0) + { + DataLabel = new DrawingTextBox(Chart, ChartRenderer.ChartArea.Rectangle.Bounds, x, y, width, height); + DataLabel.TextBody.AutoSize = false; + } + else + { + DataLabel = new DrawingTextBox(Chart, ChartRenderer.Bounds, ChartRenderer.Bounds.Width, ChartRenderer.Bounds.Height); + if (x > 0) + { + DataLabel.Left = x; + } + if (y > 0) + { + DataLabel.Top = y; + } + DataLabel.TextBody.AutoSize = true; + } + lbl.TextBody.Paragraphs[0].HorizontalAlignment = OfficeOpenXml.Drawing.eTextAlignment.Center; + DataLabel.ImportTextBodyAndParagraphs(lbl.TextBody, true, OfficeOpenXml.Style.ExcelHorizontalAlignment.Center); + var labelText = ""; + if (_trendline.DisplayEquation) + { + labelText += Formula; + } + if (_trendline.DisplayRSquaredValue) + { + if (labelText.Length > 0) + { + labelText += Environment.NewLine; + } + labelText += RSquare; + } + //lbl.TextBody.Paragraphs[0].HorizontalAlignment = OfficeOpenXml.Drawing.eTextAlignment.Center; + //DataLabel.ImportParagraph(lbl.TextBody.Paragraphs[0], 0, ""); + AddLblText(DataLabel, labelText); + DataLabel.LeftMargin = DataLabel.RightMargin = 4; + DataLabel.TopMargin = DataLabel.BottomMargin = 2; + + //Set datalabel position. + if(DataLabel.Left + 5 > ChartRenderer.Bounds.Right) + { + DataLabel.Left = ChartRenderer.Bounds.Right - DataLabel.Width - 5; + } + else + { + DataLabel.Left -= (DataLabel.Width + 5); + } + + if(DataLabel.Left<0) + { + DataLabel.Left = 0; + } + + if(DataLabel.Top - DataLabel.Height / 2 > ChartRenderer.Bounds.Bottom) + { + DataLabel.Top = ChartRenderer.Bounds.Bottom - DataLabel.Height / 2; + } + else + { + DataLabel.Top -= DataLabel.Height / 2; + } + + if (DataLabel.Top < 0) + { + DataLabel.Top = 0; + } + + + DataLabel.Rectangle.SetDrawingPropertiesFill(ChartRenderer.Theme, _trendline.Label.Fill, Chart.StyleManager.Style.TrendlineLabel.FillReference.Color, true); + DataLabel.Rectangle.SetDrawingPropertiesBorder(ChartRenderer.Theme, _trendline.Label.Border, Chart.StyleManager.Style.TrendlineLabel.BorderReference.Color, true, _trendline.Label.Border.Width); + DataLabel.Rectangle.SetDrawingPropertiesEffects(ChartRenderer.Theme, _trendline.Label.Effect); + } + + private void AddLblText(DrawingTextBox lbl, string labelText) + { + int pIx = 0; + var ix = labelText.IndexOf("|ss:"); + + while(ix>=0 && ix < labelText.Length) + { + lbl.TextBody.Paragraphs[0].AddText(labelText.Substring(pIx, ix - pIx)); + var endIx = labelText.IndexOf("|", ix + 4); + var rt = new RichTextFormatDrawing(lbl.TextBody.Paragraphs[0].DefaultParagraphFont) { SuperScript = true, Text = labelText.Substring(ix+4, endIx-ix-4)}; + lbl.TextBody.Paragraphs[0].AddRichText(rt); + pIx = endIx+1; + ix = labelText.IndexOf("|ss:", pIx); + } + + //Uncommenting this doubles the line in the case ix <0 + //Left as comment just in case there is some edge-cases + //if (ix < 0) + //{ + // lbl.TextBody.Paragraphs[0].AddText(labelText); + //} + if (pIx < labelText.Length) + { + lbl.TextBody.Paragraphs[0].AddText(labelText.Substring(pIx, labelText.Length - pIx)); + } + + //Should probably be a callback + lbl.TextBody.RecalculateParagraphs(); + lbl.TextBody.Top = lbl.TextBody.GetAlignmentVertical(); + } + + private void CalculateLinear() + { + var n = _xSerie.Count; + //var sumX = (double)n * (n + 1) / 2; + var sumY = _ySerie.Sum(y => y); + //var sumX2 = (double)n * (n + 1) * (2 * n + 1) / 6; + var sumXY = 0D; + + double slope, intercept; + if (double.IsNaN(_trendline.Intercept)) + { + var sumX = (double)n * (n + 1) / 2; + var sumX2 = (double)n * (n + 1) * (2 * n + 1) / 6; + for (int i = 0; i < _ySerie.Length; i++) + { + double x = _xSerie[i]; + sumXY += _ySerie[i] * (i+1); + } + + //Slope + slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX); + //Intercept + intercept = (sumY - slope * sumX) / n; + } + else + { + var sumX = _xSerie.Sum(x => x); + var sumX2 = _xSerie.Sum(x => x * x); + intercept = _trendline.Intercept; + for (int i = 0; i < _ySerie.Length; i++) + { + double x= _xSerie[i]; + sumXY += x * (_ySerie[i] - intercept); // x = i+1 + } + + slope = sumXY / sumX2; + } + + //var r2 = Math.Pow(Pearson.PearsonImpl(_ySerie.Cast(), GetLinearSerie(slope, intercept)), 2); + var r2 = CalculateRSquared(x => slope * x + intercept, _ySerie, _trendline.Intercept); + Coefficients = [slope, intercept]; + Formula = $"y={slope:N4}x{(GetValueAndSignSuppressZero(intercept))}"; + RSquare = $"R²={r2:N4}"; + } + + private string GetValueAndSignSuppressZero(double value) + { + if(value>0) + { + return $"+{value.ToString("G5")}"; + } + else if(value < 0) + { + return $"-{value.ToString("G5")}"; + } + return ""; + } + + private void CalculateExponential() + { + var n = _xSerie.Count; + var sumX = n * (n + 1) / 2; + var sumLnY = _ySerie.Sum(y => Math.Log(y)); + var sumX2 = n * (n + 1) * (2 * n + 1) / 6; + + var sumXLnY = 0D; + + //Slope + double slope, intercept; + if(double.IsNaN(_trendline.Intercept)) + { + for (var i = 0; i < _ySerie.Length; i++) + { + sumXLnY += Math.Log(_ySerie[i]) * (i + 1); + } + + slope = (n * sumXLnY - sumX * sumLnY) / (n * sumX2 - sumX * sumX); + //Intercept + intercept = Math.Pow(Math.E, (sumLnY - slope * sumX) / n); + } + else + { + intercept = _trendline.Intercept; + var logIntercept = Math.Log(intercept); + for (var i = 0; i < _ySerie.Length; i++) + { + sumXLnY += (Math.Log(_ySerie[i]) - logIntercept) * (i + 1); + } + + slope = sumXLnY / sumX2; + } + + + var r2 = Math.Pow(Pearson.PearsonImpl(_ySerie.Cast(), GetExponentialSerie(slope, intercept)), 2); + Coefficients = [slope, intercept]; + Formula = $"y = {intercept:G5}e|ss:{slope:G3}x| "; + RSquare = $"R² = {r2:N4} "; + } + private void CalculateLogarithmic() + { + var n = _xSerie.Count; + var logSerie = _xSerie.Select(x => Math.Log(_xSerie.IndexOf(x) + 1)).ToList(); + var sumLnX = logSerie.Sum(x => x); + var sumLnX2 = logSerie.Sum(x => x * x); + var sumY = _ySerie.Sum(x => ConvertUtil.GetValueDouble(x)); + + var sumLnXY = 0D;// _ySerie.Sum(x => ConvertUtil.GetValueDouble(x) * Math.Log(_ySerie.IndexOf(x) + 1)); + for (int i = 0; i < _ySerie.Length; i++) + { + sumLnXY += _ySerie[i] * logSerie[i]; + } + + + + //Slope + var slope = (n * sumLnXY - sumLnX * sumY) / (n * sumLnX2 - sumLnX * sumLnX); + ////Intercept + var intercept = (sumY - slope * sumLnX) / n; + + Coefficients = [slope, intercept]; + + var r2 = CalculateRSquared(x => slope * Math.Log(x) + intercept, _ySerie, _trendline.Intercept); + Formula = $"y = {slope:G5}ln(x) + {intercept:G5}"; + RSquare = $"R² = {r2:N4}"; + } + public void CalculatePolynomial() + { + + /* + Σy = c·n + b·Σx + a·Σx² + Σxy = c·Σx + b·Σx² + a·Σx³ + Σx²y = c·Σx² + b·Σx³ + a·Σx⁴ + Σx³y = c·Σx³ + b·Σx⁴ + a·Σx⁵ + ... + */ + + var isForced = double.IsNaN(_trendline.Intercept) == false; + int n = _ySerie.Length; + var order = Math.Min((int)_trendline.Order, n-1); + int coeffCount = order + (isForced ? 0 : 1); + + // Step 1: Build sums + double[] sumX = new double[2 * order + 1]; + double[] sumXY = new double[order + 1]; + + if (isForced) + { + //Todo:Add intercept to the formula and adjust the y values accordingly + var intercept = _trendline.Intercept; + double[] yAdj = new double[n]; + for (int i = 0; i < n; i++) + { + yAdj[i] = _ySerie[i] - intercept; + } + + for (int i = 0; i < n; i++) + { + double xPow = 1.0; + for (int k = 0; k <= 2 * order; k++) + { + sumX[k] += xPow; + if (k <= order) + sumXY[k] += xPow * yAdj[i]; + xPow *= i + 1; + } + } + } + else + { + for (int i = 0; i < n; i++) + { + double xPow = 1.0; + for (int k = 0; k <= 2 * order; k++) + { + sumX[k] += xPow; + if (k <= order) + sumXY[k] += xPow * _ySerie[i]; + xPow *= i + 1; + } + } + } + + // Step 2: Build augmented matrix + double[,] matrix = new double[coeffCount, coeffCount + 1]; + + int offset = isForced ? 2 : 0; + for (int row = 0; row < coeffCount; row++) + { + for (int col = 0; col < coeffCount; col++) + matrix[row, col] = sumX[row + col + offset]; + matrix[row, coeffCount] = sumXY[row + (offset / 2)]; + } + + // Step 3: Gaussian elimination with partial pivoting + for (int i = 0; i < coeffCount; i++) + { + // Find best pivot + int maxRow = i; + for (int k = i + 1; k < coeffCount; k++) + { + if (Math.Abs(matrix[k, i]) > Math.Abs(matrix[maxRow, i])) + maxRow = k; + } + + // Swap rows + for (int k = 0; k <= coeffCount; k++) + { + double temp = matrix[i, k]; + matrix[i, k] = matrix[maxRow, k]; + matrix[maxRow, k] = temp; + } + + // Divide pivot row + double pivot = matrix[i, i]; + for (int k = 0; k <= coeffCount; k++) + matrix[i, k] /= pivot; + + // Eliminate column from other rows + for (int j = 0; j < coeffCount; j++) + { + if (j != i) + { + double factor = matrix[j, i]; + for (int k = 0; k <= coeffCount; k++) + matrix[j, k] -= factor * matrix[i, k]; + } + } + } + + // Step 4: Extract coefficients + Coefficients = new double[order+1]; + if (isForced) + { + Coefficients[0] = _trendline.Intercept; + for (int i = 0; i < coeffCount; i++) + { + Coefficients[i+1] = matrix[i, coeffCount]; + } + } + else + { + for (int i = 0; i < coeffCount; i++) + { + Coefficients[i] = matrix[i, coeffCount]; + } + } + Formula = "y = " + GetPolynormFormula(); + var r2 = CalculateRSquared(x => PredictLinear(x), _ySerie, _trendline.Intercept); + RSquare = $"R² = {r2:N4}"; + } + + private void CalculatePower() + { + var n = _xSerie.Count; + var lnSerie = _xSerie.Select((x, i) => Math.Log(i + 1)); + var sumLnX = lnSerie.Sum(x => x); + var sumLnX2 = lnSerie.Sum(x => x*x); + var sumLnY = _ySerie.Sum(y => Math.Log(y)); + //double sumLnXLnY = _ySerie.Sum(y => Math.Log(ConvertUtil.GetValueDouble(y)) * Math.Log(_ySerie.IndexOf(y) + 1)); + double sumLnXLnY = 0; + for (int i=0;i < _ySerie.Length;i++) + { + sumLnXLnY += Math.Log(_ySerie[i]) * Math.Log(i + 1); + } + + var slope = (n * sumLnXLnY - sumLnX * sumLnY) / (n*sumLnX2 - sumLnX * sumLnX); + var intercept = Math.Pow(Math.E, (sumLnY - slope * sumLnX) / n); + Coefficients = [slope, intercept]; + + Formula = $"y = {intercept:G5} x |ss:{slope:G5}|"; + var ylogSerie = _ySerie.Select(y => Math.Log(y)).ToArray(); + var r2 = CalculateRSquaredPearson(x => intercept * Math.Pow(x, slope), _ySerie); + RSquare = $"R² = {r2:N4} "; + } + + private void CalculateMoveingAverage() + { + int n = _ySerie.Length; + double[] result = new double[n]; + var period = (int)(double.IsNaN(_trendline.Period) || _trendline.Period < 2 ? 2 : _trendline.Period); + for (int i = period - 1; i < n; i++) + { + double sum = 0; + for (int j = 0; j < period; j++) + sum += _ySerie[i - j]; + result[i] = sum / period; + } + + Coefficients = result; + + Formula = ""; + RSquare = ""; + } + + private string GetPolynormFormula() + { + var sb = new StringBuilder(Coefficients[0].ToString("G5")); + for (var i = 1; i < Coefficients.Length; i++) + { + if (Coefficients[i-1]>=0) + { + sb.Insert(0, " + "); + } + else + { + sb.Insert(0, " - "); + } + + if(i < 2) + { + sb.Insert(0, $"{Math.Abs(Coefficients[i]):G5}x "); + } + else + { + sb.Insert(0, $"{Math.Abs(Coefficients[i]):G5}x|ss:{i}| "); + } + } + if (Coefficients[Coefficients.Length - 1] < 0) + { + sb.Insert(0, " - "); + } + + return sb.ToString(); + } + + // Predict a y value for a given x + public double PredictLinear(double x) + { + double y = 0; + double xPow = 1.0; + for (int i = 0; i < Coefficients.Length; i++) + { + y += Coefficients[i] * xPow; + xPow *= x; + } + return y; + } + // Predict a y value for a given x + public double PredictPolynomial(double x) + { + double y = 0; + double xPow = 1.0; + for (int i = 0; i < Coefficients.Length; i++) + { + y += Coefficients[i] * xPow; + xPow *= x; + } + return y; + } + private IEnumerable GetExponentialSerie(double m, double b) + { + var l = new List() { b }; + for (var i = 1; i < _xSerie.Count; i++) + { + l.Add(b * Math.Pow(Math.E, m * i)); + } + return l; + } + public double CalculateRSquared(Func predictFunc, double[] serieY, double forcedIntercept) + { + int n = serieY.Length; + if (!double.IsNaN(forcedIntercept)) + { + // Forced intercept: use squared Pearson correlation + double meanY = serieY.Average(); + double[] predicted = new double[n]; + for (int i = 0; i < n; i++) + predicted[i] = predictFunc(i + 1); + double meanP = predicted.Average(); + + double sumYP = 0, sumY2 = 0, sumP2 = 0; + for (int i = 0; i < n; i++) + { + double dy = serieY[i] - meanY; + double dp = predicted[i] - meanP; + sumYP += dy * dp; + sumY2 += dy * dy; + sumP2 += dp * dp; + } + + double r = sumYP / Math.Sqrt(sumY2 * sumP2); + return r * r; + } + else + { + // Standard R² + double meanY = serieY.Average(); + double ssRes = 0, ssTot = 0; + for (int i = 0; i < n; i++) + { + double residual = serieY[i] - predictFunc(i + 1); + double deviation = serieY[i] - meanY; + ssRes += residual * residual; + ssTot += deviation * deviation; + } + return 1.0 - (ssRes / ssTot); + } + } + public double CalculateRSquaredPearson(Func predictFunc, double[] serieY) + { + int n = serieY.Length; + double meanA = serieY.Average(); + + double[] predicted = new double[n]; + for (int i = 0; i < n; i++) + predicted[i] = predictFunc(i + 1); + double meanP = predicted.Average(); + + double sumAP = 0, sumA2 = 0, sumP2 = 0; + for (int i = 0; i < n; i++) + { + double da = serieY[i] - meanA; + double dp = predicted[i] - meanP; + sumAP += da * dp; + sumA2 += da * da; + sumP2 += dp * dp; + } + + double r = sumAP / Math.Sqrt(sumA2 * sumP2); + return r * r; + } + public double[] Coefficients {get;set;} + public string Formula { get; set; } + public string RSquare { get; set; } + public DrawingTextBox DataLabel { get; set; } + public override string ToString() + { + return _trendline.Type + "," + Formula + "," + RSquare; + } + internal void CreateRenderCoordinatesAndDatalabel() + { + CreateRenderCoordinates(); + CreateDatalabel(); + } + public override void AppendRenderItems(List renderItems) + { + var pathItem = new PathRenderItem(ChartRenderer.Plotarea.Rectangle.Bounds); + pathItem.Commands.Add(new EPPlusImageRenderer.PathCommands(PathCommandType.Move, RenderCoordinates)); + pathItem.FillColor = "none"; + pathItem.SetDrawingPropertiesBorder(ChartRenderer.Theme, _trendline.Border, Chart.StyleManager.Style?.Trendline.BorderReference.Color, true, _trendline.Border.Width); + pathItem.SetDrawingPropertiesEffects(ChartRenderer.Theme, _trendline.Effect); + renderItems.Add(pathItem); + } + + private void CreateCoordinates(Func predictPoint) + { + var x1 = 0; + var x2 = _xSerie.Count - 1; + + //We aim for 1 line per point for the trendline. + var diff = (x2 - x1); + var inc = diff / GetXInc(ChartRenderer.Bounds.Width); + double y; + for (double d = x1; d < x2; d += inc) + { + var x = (x2) * (d - x1) / diff; + y = predictPoint(x + 1); + Coordinates.Add(new Coordinate(x,y)); + } + + y = predictPoint(x2 + 1); + Coordinates.Add(new Coordinate(x2, y)); + } + private void CreateRenderCoordinates() + { + var isBar = _chartType.IsTypeBar(); + var isLine = _chartType.IsTypeLine(); + ChartAxisRenderer catAxis, valAxis; + if(isBar) + { + valAxis = _useSecondaryAxis ? ChartRenderer.SecondHorizontalAxis : ChartRenderer.HorizontalAxis; + catAxis = _useSecondaryAxis ? ChartRenderer.SecondVerticalAxis : ChartRenderer.VerticalAxis; + } + else + { + catAxis = _useSecondaryAxis ? ChartRenderer.SecondHorizontalAxis : ChartRenderer.HorizontalAxis; + valAxis = _useSecondaryAxis ? ChartRenderer.SecondVerticalAxis : ChartRenderer.VerticalAxis; + } + + var pa = ChartRenderer.Plotarea; + var coordinates=new List(); + for (var i=0;i _ySerie.Length ? _xSerie.Count: _ySerie.Length); + var ct = (ExcelBarChart) _chartType; + var yWidth = (isBar ? ChartRenderer.Plotarea.Rectangle.Height : ChartRenderer.Plotarea.Rectangle.Width); + var slotSize = valAxis.Values.Count; + var gapPercent = ct.GapWidth / 100D; // Gap width between bars/columns in percent + var overlapPercent = ct.Overlap / 100D; // Overlap between bars/columns in percent + var slotWidth = yWidth / slotSize; + var clusterWidth = slotWidth * 100 / (100 + ct.GapWidth); + var step = 1 - overlapPercent; + var barWidth = slotWidth / (1 + (count - 1) * step + gapPercent); + var halfGap = (barWidth * gapPercent) / 2; + if (isBar) + { + + coordinates.Add(valAxis.GetPositionInPlotarea(Coordinates[i].Y)); + coordinates.Add(catAxis.GetPositionInPlotarea(Coordinates[Coordinates.Count - 1].X - Coordinates[i].X) + halfGap + (_serieCount - _seriePos - 1) * barWidth * step); + } + else + { + coordinates.Add(catAxis.GetPositionInPlotarea(Coordinates[i].X)); + coordinates.Add(valAxis.GetPositionInPlotarea(Coordinates[i].Y)); + } + } + } + RenderCoordinates = coordinates.ToArray(); + } + + //Get the incremental x value for the trendline points based on the distance between the start and end point of the trendline. The goal is to have approximately 3 point per data point in the trendline. + private double GetXInc(double n) + { + int k = (int)Math.Round(Math.Log(n)/ Math.Log(3) - 1); + k = Math.Max(k, 0); + return n / Math.Pow(2, k); + } + internal List Coordinates { get; set; } = new List(); + internal double[] RenderCoordinates { get; set; } + List _ma = null; + private double GetMonthlyAverageAtPosition(double x) + { + if (_ma == null) + { + CalcMa((int)_trendline.Period); + } + + int ix = (int)(x - _trendline.Period + 1); + return _ma[ix]; + } + + private void CalcMa(int period) + { + _ma= new List(); + double sum = 0; + for (int i=0;i < _ySerie.Length;i++) + { + sum += _ySerie[i]; + if (i >= period - 1) + { + + _ma.Add(sum / period); + sum -= _ySerie[i - period + 1]; + } + } + } + + private double GetLinearValueAtPosition(double x) + { + return Coefficients[1] + Coefficients[0] * x; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/DataLabels/ChartSerieDataLabelRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/ChartSerieDataLabelRenderer.cs new file mode 100644 index 0000000000..8b44fceca3 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/ChartSerieDataLabelRenderer.cs @@ -0,0 +1,173 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Utils.TypeConversion; +using System.Collections.Generic; +using System.Drawing; + +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + internal class ChartSerieDataLabelRenderer : ChartDrawingObject + { + //positioning is handled by parent item via these + private List dataLabels = new List(); + + private RenderItem seriesIcon = null; + private int _serieIndex = -1; + ExcelDrawingParagraph defaultParagraph; + BoundingBox plotAreaBounds; + BoundingBox _defaultMargins; + ExcelChartSerieDataLabel _dlblSerie; + + internal double rotation = double.NaN; + internal Graphics.Point rotationPoint = null; + + public ChartSerieDataLabelRenderer(ChartRenderer chart, ExcelChartSerieDataLabel dlblSerie, BoundingBox maxBounds, ExcelChartStandardSerie serie, List xValues, List yValues, int index) : base(chart) + { + _serieIndex = index; + _dlblSerie = dlblSerie; + plotAreaBounds = chart.Plotarea.Group.Bounds; + + if (dlblSerie.TextBody.Paragraphs.Count != 0) + { + defaultParagraph = dlblSerie.TextBody.Paragraphs[0]; + } + + dlblSerie.TextBody.GetInsetsInPoints(out double l, out double top, out double right, out double bottom); + _defaultMargins = new BoundingBox(l, top, right, bottom); + + if (dlblSerie.DataLabels.Count == 0 && serie.NumberOfItems > 0) + { + for (int i = 0; i < serie.NumberOfItems; i++) + { + var yVal = yValues == null ? null : yValues[i]; + var xVal = xValues == null ? null : xValues[i]; + AddDatalabel(serie, dlblSerie, xVal, yValues[i], maxBounds); + } + } + else + { + int nextIndex = dlblSerie.DataLabels[0].Index; + var customIndex = 0; + for (int i = 0; i < serie.NumberOfItems; i++) + { + if (i == nextIndex) + { + var dataLabel = dlblSerie.DataLabels[customIndex++]; + var individualIndex = dataLabel.Index; + var yVal = yValues == null ? null : yValues[i]; + var xVal = xValues == null ? null : xValues[i]; + AddDatalabel(serie, dataLabel, xVal, yVal, maxBounds); + + if (customIndex < dlblSerie.DataLabels.Count) + { + nextIndex = dlblSerie.DataLabels[customIndex].Index; + } + } + else + { + var yVal = yValues == null ? null : yValues[i]; + var xVal = xValues == null ? null : xValues[i]; + AddDatalabel(serie, dlblSerie, xVal, yValues[i], maxBounds); + } + } + } + } + + private void CreateSeriesIcon(ExcelChartStandardSerie serie, BoundingBox maxBounds) + { + if (ChartRenderer.Legend == null) + { + seriesIcon = ChartRenderer.GetSeriesIcon(serie, _serieIndex, maxBounds); + } + else + { + var legendItem = ChartRenderer.Legend; + var seriesIconOrig = (LineRenderItem)legendItem.SeriesIcon[_serieIndex].SeriesIcon; + var clonedIcon = seriesIconOrig.Clone(); + + clonedIcon.Y1 = 0; + clonedIcon.Y2 = 0; + + seriesIcon = clonedIcon; + } + } + + private RenderItem GetSeriesIcon(ExcelChartStandardSerie serie, BoundingBox maxBounds) + { + if(seriesIcon == null) + { + CreateSeriesIcon(serie, maxBounds); + } + + return seriesIcon; + } + + private void AddDatalabel(ExcelChartStandardSerie serie, ExcelChartDataLabelStandard dataLabel, object xValue, object yValue, BoundingBox maxBounds) + { + var newDataLabel = new SvgDataLabelPoint(ChartRenderer, dataLabel); + newDataLabel.ImportDataLabel(serie, dataLabel, xValue, yValue, defaultParagraph, maxBounds, _defaultMargins); + + if(dataLabel.ShowLegendKey) + { + newDataLabel.AddSeriesIcon(GetSeriesIcon(serie, maxBounds)); + } + + dataLabels.Add(newDataLabel); + } + + internal void SetDimensions(int index, Transform basePoint, Transform endPoint) + { + if (dataLabels.Count > index) + { + dataLabels[index].SetShapeDimensions(basePoint, endPoint); + } + } + + internal void SetParentPoint(BoundingBox parent, int index) + { + if (dataLabels.Count > index) + { + dataLabels[index].SetParentPoint(parent); + } + } + + public override void AppendRenderItems(List renderItems) + { + var plotAreaGroup = new GroupRenderItem(plotAreaBounds); + + plotAreaGroup.Left = plotAreaBounds.Position.X; + plotAreaGroup.Top = plotAreaBounds.Position.Y; + + if(rotation != double.NaN) + { + if(rotationPoint != null) + { + plotAreaGroup.RotationPoint = rotationPoint; + } + plotAreaGroup.Rotation = rotation; + } + + if (_dlblSerie.Fill.IsEmpty == false) + { + Rectangle.SetDrawingPropertiesFill(ChartRenderer.Theme, _dlblSerie.Fill, null); + plotAreaGroup.SetDrawingPropertiesFill(ChartRenderer.Theme, _dlblSerie.Fill, null); + } + + renderItems.Add(plotAreaGroup); + for(int i = 0; i< dataLabels.Count; i++) + { + if(rotation != double.NaN) + { + dataLabels[i].CounterRotation = -rotation; + } + dataLabels[i].AppendRenderItems(plotAreaGroup.RenderItems); + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/DataLabels/PointLines.cs b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/PointLines.cs new file mode 100644 index 0000000000..a4767f8a12 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/PointLines.cs @@ -0,0 +1,63 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.Svg; +using System.Collections.Generic; + +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + internal class PointLines : ChartDrawingObject + { + internal List RenderLines = new List(); + + internal ConnectionPointsMiddle ConnectionPoints; + + private List ptColors = new List { "red", "green", "blue", "yellow" }; + + private BoundingBox parentBounds; + + private PointLines(ChartRenderer cr) : base(cr) + { + Rectangle = new RectRenderItem(cr.Bounds); + } + + internal PointLines(ChartRenderer cr, BoundingBox parent, ConnectionPointsMiddle connectionPoints) : this(cr) + { + parentBounds = parent; + + Rectangle.Bounds.Parent = parent; + ConnectionPoints = connectionPoints; + + UpdateLines(); + } + + internal void UpdateLines() + { + RenderLines.Clear(); + + for (int i = 0; i < ConnectionPoints.Points.Count; i++) + { + var cPoint = ConnectionPoints.Points[i]; + var cPointLine = new LineRenderItem(Rectangle.Bounds); + cPointLine.X1 = 0; + cPointLine.Y1 = 0; + cPointLine.X2 = cPoint.X; + cPointLine.Y2 = cPoint.Y; + + cPointLine.BorderWidth = 1; + cPointLine.BorderColor = ptColors[i]; + RenderLines.Add(cPointLine); + } + } + + public override void AppendRenderItems(List renderItems) + { + GroupRenderItem gItem = new GroupRenderItem(Rectangle.Bounds); + renderItems.Add(gItem); + foreach (var line in RenderLines) + { + gItem.RenderItems.Add(line); + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/DataLabels/SvgDataLabelPoint.cs b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/SvgDataLabelPoint.cs new file mode 100644 index 0000000000..2222af6c02 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DataLabels/SvgDataLabelPoint.cs @@ -0,0 +1,590 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; + +namespace EPPlus.Export.ImageRenderer.RenderItems.SvgItem +{ + internal class SvgDataLabelPoint : ChartDrawingObject + { + bool _hasManualLayout = false; + bool _hasLeaderLines = false; + bool _haveAdjustedForIcon = false; + bool _renderConnectionPointLines = false; + + private DrawingTextBox _txtBox; + BoundingBox _parentPoint; + List _leaderLines = new List(); + Coordinate _manualLayoutOffset = new Coordinate (0, 0); + PointLines _connectionPointLines; + eLabelPosition _labelPosition; + internal double CounterRotation = double.NaN; + + //public SvgChartDataLabelStandard(DrawingChart chart, string dataLabelText) : base(chart) + //{ + // var txtBox = new SvgTextBox(chart, chart.Bounds, chart.Bounds); + // txtBox.AddText(0, dataLabelText); + //} + + //public SvgChartDataLabelStandard(DrawingChart chart, ExcelChartDataLabelStandard standard, SvgTextBox txtBox) : base(chart) + //{ + // HasLegendKey = standard.ShowLegendKey; + // TxtBox = txtBox; + //} + + public SvgDataLabelPoint(ChartRenderer chart, ExcelChartDataLabelStandard standard) : base(chart) + { + _labelPosition = standard.Position; + Rectangle = new RectRenderItem(chart.Bounds); + } + + RenderItem _seriesIcon = null; + + internal void AddSeriesIcon(RenderItem seriesIcon) + { + var iconWidth = seriesIcon.Bounds.Width; + var iconHeight = seriesIcon.Bounds.Height; + + _seriesIcon = seriesIcon; + _seriesIcon.Bounds.Parent = Rectangle.Bounds; + + if (_haveAdjustedForIcon == false) + { + _txtBox.Left += iconWidth; + _seriesIcon.Bounds.Left -= 0.75d; + //It seems there is a hard-coded margin in excel of about 4.5pt (6px) + Rectangle.Bounds.Left += 4d + 2.25d; + LeftMargin -= 2.25d + 4d; + Rectangle.Bounds.Width += iconWidth + 2.25d; + + _haveAdjustedForIcon = true; + } + } + + internal void ImportDataLabel(ExcelChartStandardSerie serie, ExcelChartDataLabelStandard dataLabel, object xValue, object yValue, ExcelDrawingParagraph defaultParagraph, BoundingBox maxBounds, BoundingBox defaultMargins) + { + List dlblStrings = new List(); + + if (dataLabel.ShowSeriesName) + { + dlblStrings.Add(serie.GetHeaderString()); + } + if (dataLabel.ShowCategory) + { + dlblStrings.Add(xValue.ToString()); + } + if (dataLabel.ShowValue) + { + if (yValue != null) + { + dlblStrings.Add(yValue.ToString()); + } + } + + var separator = string.IsNullOrEmpty(dataLabel.Separator) ? ", " : dataLabel.Separator; + + string finalString = ""; + for (int j = 0; j < dlblStrings.Count; j++) + { + finalString += dlblStrings[j]; + if (j != dlblStrings.Count - 1) + { + finalString += separator; + } + } + + var txtBox = new DrawingTextBox(Chart, Rectangle.Bounds, maxBounds.Width, maxBounds.Height); + + txtBox.ImportTextBodyAndParagraphs(dataLabel.TextBody, false); + + txtBox.TextBody.Bounds.Top = 0; + txtBox.TextBody.AutoSize = true; + + if (txtBox.TextBody.Paragraphs.Count == 0) + { + if(defaultParagraph == null) + { + txtBox.TextBody.AddParagraph(finalString); + } + else + { + txtBox.ImportParagraph(defaultParagraph, 0, finalString); + } + //txtBox.TextBody.AddParagraph(0, finalString); + } + else if (txtBox.TextBody.Paragraphs.Count == 1) + { + txtBox.ImportParagraph(dataLabel.TextBody.Paragraphs[0], 0, finalString); + //Remove dummy paragraph added by ImportTextBody + txtBox.TextBody.Paragraphs.RemoveAt(0); + } + + txtBox.TextBody.RecalculateParagraphs(); + + if(txtBox.LeftMargin == 0) + { + txtBox.LeftMargin = defaultMargins.Left; + txtBox.RightMargin = defaultMargins.Width; + txtBox.TopMargin = defaultMargins.Top; + txtBox.BottomMargin = defaultMargins.Height; + } + + ////Txtbox is Broken. Workaround + //txtBox.Left += txtBox.LeftMargin; + //txtBox.Top += txtBox.TopMargin; + + //Center the textbox at the origin point + Rectangle.Bounds.Left -= txtBox.Rectangle.Bounds.Width / 2; + Rectangle.Bounds.Top -= txtBox.Rectangle.Bounds.Height / 2; + + //Set initial width and height to content + Rectangle.Bounds.Width = txtBox.Rectangle.Bounds.Width; + Rectangle.Bounds.Height = txtBox.Rectangle.Bounds.Height; + + _txtBox = txtBox; + + if (dataLabel.Fill.IsEmpty == false) + { + _txtBox.Rectangle.SetDrawingPropertiesFill(ChartRenderer.Theme, dataLabel.Fill, null); + } + //else + //{ + // _txtBox.Rectangle.SetDrawingPropertiesFill(ChartRenderer.Theme, dataLabel.Fill, null); + // _txtBox.Rectangle.FillColor = "transparent"; + //} + + if (dataLabel.Font.IsEmpty == false) + { + txtBox.TextBody.FontColorString = "#" + dataLabel.Font.Color.ToColorString(); + } + + _labelPosition = dataLabel.Position; + + if (dataLabel is ExcelChartDataLabelItem) + { + var individualLabel = dataLabel as ExcelChartDataLabelItem; + + if (individualLabel.Fill.IsEmpty == false) + { + _txtBox.Rectangle.FillColor = "#" + individualLabel.Fill.Color.ToColorString(); + } + + if (individualLabel.Layout != null && individualLabel.Layout.HasLayout) + { + _hasManualLayout = true; + var rect = GetRectFromManualLayout(ChartRenderer, individualLabel.Layout); + + Rectangle.Bounds.Left += rect.Left; + Rectangle.Bounds.Top += rect.Top; + + _manualLayoutOffset = new Coordinate(rect.Left, rect.Top); + + if (rect.Bounds.Width != 0) + { + Rectangle.Bounds.Width = rect.Bounds.Width; + } + if (rect.Bounds.Height != 0) + { + Rectangle.Bounds.Height = rect.Bounds.Height; + } + + if (dataLabel.ShowLeaderLines) + { + _hasLeaderLines = true; + } + } + } + } + + private int GetClosestConnectionPointCoordinateIndex(Coordinate originPoint) + { + double smallestDist = double.MaxValue; + int i = 0; + int smallestIndex = 0; + + foreach (var line in _connectionPointLines.RenderLines) + { + line.X1 = originPoint.X; + line.Y1 = originPoint.Y; + + var w = Math.Abs(line.X2 - line.X1); + var h = Math.Abs(line.Y2 - line.Y1); + + //Use pythagoran theorem to get diagonal distance + var totalDist = Math.Sqrt(Math.Pow(w, 2) + Math.Pow(h, 2)); + + if (totalDist < smallestDist) + { + smallestDist = totalDist; + smallestIndex = i; + } + i++; + } + + return smallestIndex; + } + + private void SetPositionBasic(BoundingBox point, eLabelPosition basicPosition) + { + switch (basicPosition) + { + //case eLabelPosition.Center: + // Bounds.Left = dataLabelCenter.X; + // Bounds.Top = dataLabelCenter.Y; + // break; + case eLabelPosition.Left: + Rectangle.Bounds.Left -= (_txtBox.Width/2) + (point.Width / 2d); + break; + case eLabelPosition.Right: + case eLabelPosition.BestFit: + Rectangle.Bounds.Left += (_txtBox.Width / 2d) + point.Width; + break; + case eLabelPosition.Top: + Rectangle.Bounds.Top -= (point.Height + _txtBox.Height) / 2d; + break; + case eLabelPosition.Bottom: + Rectangle.Bounds.Top += (point.Height + _txtBox.Height) / 2d; + break; + default: + throw new InvalidOperationException($"The datalabel position entered in SetPositionBasic: '{basicPosition}' is not a basic position"); + } + } + + + RectRenderItem originPointRect; + RectRenderItem basePositionRect; + RectRenderItem endPositionRect; + RectRenderItem centerPositionRect; + + + private RectRenderItem GenerateDebugRenderItem(BoundingBox parent, string fillColor) + { + var pointRect = new RectRenderItem(parent); + pointRect.Width = 10d; + pointRect.Height = 10d; + pointRect.FillColor = fillColor; + pointRect.Left = -5d; + pointRect.Top = -5d; + return pointRect; + } + + + private void CreateDebugPoints(Transform basePoint, Transform endPoint, Transform centerPoint) + { + originPointRect = GenerateDebugRenderItem(_parentPoint, "darkRed"); + basePositionRect = GenerateDebugRenderItem(_parentPoint, "darkGreen"); + basePositionRect.Left += basePoint.LocalPosition.X; + basePositionRect.Top += basePoint.LocalPosition.Y; + endPositionRect = GenerateDebugRenderItem(_parentPoint, "darkBlue"); + endPositionRect.Left += endPoint.LocalPosition.X; + endPositionRect.Top += endPoint.LocalPosition.Y; + endPositionRect.BorderWidth = 2d; + endPositionRect.BorderColor = "cyan"; + centerPositionRect = GenerateDebugRenderItem(_parentPoint, "Purple"); + centerPositionRect.Left += centerPoint.LocalPosition.X; + centerPositionRect.Top += centerPoint.LocalPosition.Y; + } + private void SetAdjustedTextBoxPosition(Vector2 direction, bool reverseDirection) + { + if(reverseDirection) + { + direction *= -1; + } + + //Ensure vector is normalized + var directionOnly = direction / direction.Length; + + //Get txtbox-size based vector + var txtBoxAdjustVector = new Vector2(_txtBox.Width / 2d, _txtBox.Height / 2d); + + //Apply translation to current position + Rectangle.Bounds.Position += directionOnly * txtBoxAdjustVector; + } + + private void SetInOut(Vector2 direction, Vector2 translation, bool reverseDirection) + { + //Translate to the translation point + Rectangle.Bounds.Position += translation; + SetAdjustedTextBoxPosition(direction, reverseDirection); + } + + /// + /// + /// + internal void SetShapeDimensions(Transform basePoint, Transform endPoint) + { + if(basePoint.Parent != endPoint.Parent) + { + throw new InvalidOperationException("basePoint and endPoint have different parents. " + + "Please ensure that they share the same parent"); + } + + + //--- Set parent point --- + _parentPoint = new BoundingBox(); + _parentPoint.Parent = basePoint.Parent.Parent; + _parentPoint.Left = basePoint.Parent.LocalPosition.X; + _parentPoint.Top = basePoint.Parent.LocalPosition.Y; + Rectangle.Bounds.Parent = _parentPoint; + //--- + + //--- Calculate vectors and center point --- + var endVector = endPoint.LocalPosition; + var baseVector = basePoint.LocalPosition; + + var endToBaseVector = baseVector - endVector; + var centerVector = endToBaseVector * 0.5d; + + //Translate from end point towards base point by 50% to find the center point + Transform centerPoint = new Transform(endPoint.LocalPosition + centerVector, endPoint.LocalPosition + centerVector); + centerPoint.Parent = basePoint.Parent; + //--- + + //At this point our rectangle globally is centered on the top-left of the object. + //And endVector is the top center position. + + //--- Visualize positions for debugging purposes + //CreateDebugPoints(basePoint, endPoint, centerPoint); + //--- + + switch (_labelPosition) + { + case eLabelPosition.Center: + Rectangle.Bounds.Left += centerPoint.LocalPosition.X; + Rectangle.Bounds.Top += centerPoint.LocalPosition.Y; + break; + case eLabelPosition.Left: + SetPositionBasic(_parentPoint, _labelPosition); + break; + case eLabelPosition.Right: + SetPositionBasic(_parentPoint, _labelPosition); + break; + case eLabelPosition.Top: + SetPositionBasic(_parentPoint, _labelPosition); + break; + case eLabelPosition.Bottom: + SetPositionBasic(_parentPoint, _labelPosition); + break; + case eLabelPosition.InBase: + SetInOut(endToBaseVector, basePoint.LocalPosition, true); + break; + case eLabelPosition.InEnd: + SetInOut(endToBaseVector, endPoint.LocalPosition, false); + break; + case eLabelPosition.OutEnd: + SetInOut(endToBaseVector, endPoint.LocalPosition, true); + break; + //Only available in charts that include pie chart + case eLabelPosition.BestFit: + //Try to fit within object if possible. If not then as close to it as possible? + + //var labelVector = new Vector2(_txtBox.Width, _txtBox.Height); + bool CanFitWidth = _txtBox.Width < Math.Abs(endToBaseVector.X); + bool CanFitHeight = _txtBox.Height < Math.Abs(endToBaseVector.Y); + if (CanFitWidth && CanFitHeight) + { + //TODO: make input parameter in pie chart + bool canFitInCenter = false; + if (canFitInCenter) + { + Rectangle.Bounds.Left += centerPoint.LocalPosition.X; + Rectangle.Bounds.Top += centerPoint.LocalPosition.Y; + } + else + { + //Set inside End + SetInOut(endToBaseVector, endPoint.LocalPosition, false); + } + } + else + { + //Set outside end + SetInOut(endToBaseVector, endPoint.LocalPosition, true); + } + break; + default: + throw new InvalidOperationException($"The datalabel position {_labelPosition} has not been implemented yet"); + } + } + + internal void SetParentPoint(BoundingBox parentPoint) + { + Rectangle.Bounds.Parent = parentPoint; + _parentPoint = parentPoint; + + var dataLabelCenter = new Vector2(Rectangle.Bounds.Left, Rectangle.Bounds.Top); + + switch (_labelPosition) + { + case eLabelPosition.Center: + Rectangle.Bounds.Left += Rectangle.Bounds.Left; + Rectangle.Bounds.Top += Rectangle.Bounds.Top; + break; + case eLabelPosition.Left: + SetPositionBasic(parentPoint, _labelPosition); + break; + case eLabelPosition.Right: + case eLabelPosition.BestFit: + SetPositionBasic(parentPoint, _labelPosition); + break; + case eLabelPosition.Top: + SetPositionBasic(parentPoint, _labelPosition); + break; + case eLabelPosition.Bottom: + SetPositionBasic(parentPoint, _labelPosition); + break; + default: + throw new InvalidOperationException($"The datalabel position {_labelPosition} has not been implemented yet"); + } + + if (_hasManualLayout) + { + if (_hasLeaderLines) + { + //With origin in top left of current bounds get the connection points + var cPoints = new ConnectionPointsMiddle(0, 0, Rectangle.Bounds.Width, Rectangle.Bounds.Height); + + //Ready to draw the lines so that we can visualize the distances to each point + _connectionPointLines = new PointLines(ChartRenderer, Rectangle.Bounds, cPoints); + + //Adjust if there is a margin + _connectionPointLines.Rectangle.Bounds.Left += LeftMargin; + _connectionPointLines.UpdateLines(); + + //Get the offset between those points and the origin point + var offsetToParentPoint = new Coordinate(-(Rectangle.Bounds.Left + LeftMargin), -(Rectangle.Bounds.Top + TopMargin)); + + //Calculate closest point + var index = GetClosestConnectionPointCoordinateIndex(offsetToParentPoint); + + _leaderLines.Clear(); + + double xOffset = 0; + if (index == 0 || index == 2) + { + //If Left or Right + //Add extra 7 px (5.25pt) line to the given side + var extraLine = new LineRenderItem(ChartRenderer.Bounds); + + xOffset += index == 0 ? -5.25d : 5.25d; + + extraLine.X1 = _connectionPointLines.ConnectionPoints.Points[index].X + LeftMargin; + extraLine.Y1 = _connectionPointLines.ConnectionPoints.Points[index].Y; + extraLine.Y2 = _connectionPointLines.ConnectionPoints.Points[index].Y; + extraLine.X2 = extraLine.X1 + xOffset; + + extraLine.BorderColor = "gray"; + extraLine.BorderWidth = 0.5; + + _leaderLines.Add(extraLine); + } + var mainLine = new LineRenderItem(ChartRenderer.Bounds); + mainLine.X1 = _connectionPointLines.ConnectionPoints.Points[index].X + xOffset + LeftMargin; + mainLine.Y1 = _connectionPointLines.ConnectionPoints.Points[index].Y; + mainLine.X2 = offsetToParentPoint.X + LeftMargin; + mainLine.Y2 = offsetToParentPoint.Y; + + mainLine.BorderColor = "gray"; + mainLine.BorderWidth = 0.5; + _leaderLines.Add(mainLine); + } + } + } + + private void AppendDebugBounds(List renderItems) + { + var rect = new RectRenderItem(Rectangle.Bounds); + rect.Bounds.Left = LeftMargin; + rect.Bounds.Top = 0; + rect.Bounds.Width = Rectangle.Bounds.Width; + rect.Bounds.Height = Rectangle.Bounds.Height; + + rect.FillColor = "red"; + rect.FillOpacity = 0.2; + renderItems.Add(rect); + } + + public override void AppendRenderItems(List renderItems) + { + var parentPointGroup = new GroupRenderItem(_parentPoint); + parentPointGroup.Left = _parentPoint.Left; + parentPointGroup.Top = _parentPoint.Top; + + var titleItemOrigin = new TitleRenderItem("DataLabel originpoint"); + parentPointGroup.AddChildItem(titleItemOrigin); + + if(originPointRect != null) + { + parentPointGroup.AddChildItem(originPointRect); + } + if(basePositionRect != null) + { + parentPointGroup.AddChildItem(basePositionRect); + } + if(endPositionRect != null) + { + parentPointGroup.AddChildItem(endPositionRect); + } + if(centerPositionRect != null) + { + parentPointGroup.AddChildItem(centerPositionRect); + } + + renderItems.Add(parentPointGroup); + + var group = new GroupRenderItem(Rectangle.Bounds); + group.Left = Rectangle.Bounds.Left; + group.Top = Rectangle.Bounds.Top; + + var titleItem = new TitleRenderItem("DataLabel size adjustment"); + group.AddChildItem(titleItem); + + parentPointGroup.RenderItems.Add(group); + + group.RotationPoint = new Graphics.Point(_txtBox.Left + (_txtBox.Width / 2), _txtBox.Top + (_txtBox.Height / 2)); + group.Rotation = CounterRotation; + + _txtBox.AppendRenderItems(group.RenderItems); + + if(_renderConnectionPointLines) + { + if (_connectionPointLines != null) + { + _connectionPointLines.AppendRenderItems(group.RenderItems); + } + } + + if (_seriesIcon != null) + { + var height = Rectangle.Bounds.Height; + if (height == 0) + { + height = _txtBox.Height; + } + //Currently series icon always has a y1 y2 of 2 + var iconGrp = new GroupRenderItem(new BoundingBox(_seriesIcon.Bounds.Left, height / 2)); + iconGrp.Left = _seriesIcon.Bounds.Left; + iconGrp.Top = (height / 2) - 2; + group.RenderItems.Add(iconGrp); + iconGrp.RenderItems.Add(_seriesIcon); + } + + if (_leaderLines != null && _leaderLines.Count > 0) + { + foreach (var line in _leaderLines) + { + group.RenderItems.Add(line); + } + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/DrawingChart.cs b/src/EPPlus/Drawing/Renderer/Chart/DrawingChart.cs new file mode 100644 index 0000000000..8b15aeb44a --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DrawingChart.cs @@ -0,0 +1,291 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +using EPPlus.Export.ImageRenderer.Svg.Chart; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Utils; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Export.HtmlExport.Exporters.Internal; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Interfaces.Drawing.Text; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +namespace EPPlusImageRenderer.Svg +{ + internal class DrawingChart : ChartRenderer + { + public DrawingChart(ExcelChart chart/*, IChartRenderer renderer*/) : base(chart) + { + SetChartArea(); + + if(chart.HasTitle && chart.Series.Count > 0) + { + Title = new SvgChartTitle(this, (ExcelChartTitleStandard)chart.Title, "Chart Title"); + } + else + { + Title = null; + } + + //We need to create the plotarea before the legend and axes, as the trendlines can affect the value axis and should be rendererd in the legend. + Plotarea = new SvgChartPlotarea(this); + Plotarea.ChartTypeDrawers = ChartTypeDrawer.Create(this); + + if (chart.HasLegend) + { + Legend = new SvgChartLegend(this); + } + else + { + Legend = null; + } + + if (Chart.Axis.Length != 0) + { + HorizontalAxis = GetAxis(false); + VerticalAxis = GetAxis(true); + } + + if(chart.Axis.Length > 2) + { + SecondVerticalAxis = GetAxis(true, 2); + SecondHorizontalAxis = GetAxis(false, 2); + } + + Plotarea.SetPlotAreaRectangle(this); + + //As we need the plotarea dimensions to calculate the axis positions we need to set the axis positions after creating the plotarea. + SetAxisPositionsFromPlotarea(this); + + Plotarea.DrawSeries(); + } + + private SvgChartAxis GetAxis(bool vertical, int offset=0) + { + var axis = (ExcelChartAxisStandard)Chart.Axis[offset]; + if(axis.IsVertical==vertical) + { + return new SvgChartAxis(this, axis); + } + else if(Chart.Axis.Length > offset + 1) + { + axis = (ExcelChartAxisStandard)Chart.Axis[offset + 1]; + if(axis.IsVertical==vertical) + { + return new SvgChartAxis(this, axis); + } + } + return null; + } + + private void SetAxisPositionsFromPlotarea(DrawingChart sc) + { + if(Legend !=null && (sc.Chart.Legend.Position==eLegendPosition.Left || sc.Chart.Legend.Position == eLegendPosition.Right)) + { + Legend.Rectangle.Top = sc.Plotarea.Rectangle.Top + (sc.Plotarea.Rectangle.Height / 2) - (Legend.Rectangle.Height / 2); + } + if(VerticalAxis != null) + { + PlaceVerticalAxis(sc, VerticalAxis); + VerticalAxis.AddTickmarksAndValues(DefItems); + } + + if (HorizontalAxis!=null && HorizontalAxis.Rectangle != null) + { + PlaceHorizontalAxis(sc, HorizontalAxis); + + //Make sure the horizontal axis is moved up if the vertical axis has a negative minimum value, so that the 0 value is at the correct position. + if (VerticalAxis.Axis.AxisType == eAxisType.Val && VerticalAxis.Min < 0D) + { + var newtop = VerticalAxis.GetPositionInPlotarea(0D) + sc.Plotarea.Rectangle.Top; + var topDiff = HorizontalAxis.Rectangle.Top - newtop; + HorizontalAxis.Rectangle.Top = newtop; + HorizontalAxis.Rectangle.Height += topDiff; + HorizontalAxis.Line.Y1 = HorizontalAxis.Line.Y2 = newtop; + } + + HorizontalAxis.AddTickmarksAndValues(DefItems); + } + + if (SecondVerticalAxis!=null) + { + PlaceVerticalAxis(sc, SecondVerticalAxis); + SecondVerticalAxis.AddTickmarksAndValues(DefItems); + } + + if (SecondHorizontalAxis != null && SecondHorizontalAxis.Rectangle != null) + { + PlaceHorizontalAxis(sc, SecondHorizontalAxis); + SecondHorizontalAxis.AddTickmarksAndValues(DefItems); + } + } + + private void PlaceHorizontalAxis(DrawingChart sc, SvgChartAxis horizontalAxis) + { + horizontalAxis.Rectangle.Width = Plotarea.Rectangle.Width; + horizontalAxis.Rectangle.Left = Plotarea.Rectangle.Left; + horizontalAxis.Line.X1 = (float)horizontalAxis.Rectangle.Left; + horizontalAxis.Line.X2 = (float)horizontalAxis.Rectangle.Right; + + if (horizontalAxis.Axis.AxisPosition == eAxisPosition.Bottom) + { + horizontalAxis.Rectangle.Top = Plotarea.Rectangle.Bottom; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = (float)Plotarea.Rectangle.Bottom; + } + else + { + horizontalAxis.Rectangle.Top = Plotarea.Rectangle.Top - horizontalAxis.Rectangle.Height; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = (float)Plotarea.Rectangle.Top; + } + + if (horizontalAxis.Title != null) + { + horizontalAxis.Title.Rectangle.Height = sc.Bounds.Height / 4; + horizontalAxis.Title.Rectangle.Width = horizontalAxis.Rectangle?.Width ?? sc.Plotarea.Rectangle.Width; + //horizontalAxis.Title.InitTextBox(); + if (horizontalAxis.Axis.AxisPosition == eAxisPosition.Bottom) + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Bottom; + } + else + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Top - horizontalAxis.Title.TextBox.Height; + } + horizontalAxis.Title.TextBox.Left = Plotarea.Rectangle.Left + (Plotarea.Rectangle.Width / 2) - (horizontalAxis.Title.TextBox.Width / 2); + } + } + + private void PlaceVerticalAxis(DrawingChart sc, SvgChartAxis verticalAxis) + { + if (verticalAxis.Rectangle != null) + { + verticalAxis.Rectangle.Top = Plotarea.Rectangle.Top; + verticalAxis.Rectangle.Height = Plotarea.Rectangle.Height; + verticalAxis.Line.Y1 = (float)verticalAxis.Rectangle.Top; + verticalAxis.Line.Y2 = (float)verticalAxis.Rectangle.Bottom; + if (verticalAxis.Axis.AxisPosition == eAxisPosition.Left) + { + verticalAxis.Rectangle.Left = Plotarea.Rectangle.Left - verticalAxis.Rectangle.Width; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Rectangle.Left; + } + else + { + verticalAxis.Rectangle.Left = Plotarea.Rectangle.Right; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Rectangle.Right; + } + } + + if (verticalAxis.Title != null) + { + //verticalAxis.Title.Rectangle.Height = Plotarea.Rectangle.Height; + //verticalAxis.Title.Rectangle.Width = sc.Bounds.Width / 4; + //verticalAxis.Title.InitTextBox(); + var sinRot = Math.Abs(Math.Sin(MathHelper.Radians(verticalAxis.Title.TextBox.Rotation))); + var cosRot = Math.Abs(Math.Cos(MathHelper.Radians(verticalAxis.Title.TextBox.Rotation))); + verticalAxis.Title.TextBox.Top = Plotarea.Rectangle.Top + (Plotarea.Rectangle.Height / 2) + ((verticalAxis.Title.TextBox.Height * cosRot + verticalAxis.Title.TextBox.Width * sinRot) / 2); + + if (verticalAxis.Axis.AxisPosition == eAxisPosition.Left) + { + if (verticalAxis.Rectangle == null) + { + verticalAxis.Title.TextBox.Left = sc.Plotarea.Rectangle.Left - verticalAxis.Title.TextBox.GetActualWidth() - 1.5; + } + else + { + verticalAxis.Title.TextBox.Left = verticalAxis.Rectangle.Left - verticalAxis.Title.TextBox.GetActualWidth() - 1.5; + } + } + else + { + if (verticalAxis.Rectangle == null) + { + verticalAxis.Title.TextBox.Left = Plotarea.Rectangle.Right; + } + else + { + verticalAxis.Title.TextBox.Left = verticalAxis.Rectangle.Right; + } + } + //verticalAxis.Title.RenderTextbox.TextAnchor = eTextAnchor.Middle; + } + } + + internal ChartDrawingObject ChartArea { get; set; } + internal SvgChartLegend Legend { get; set; } + internal SvgChartTitle Title { get; set; } + internal SvgChartPlotarea Plotarea { get; set; } + internal SvgChartAxis VerticalAxis { get; set; } + internal SvgChartAxis HorizontalAxis { get; set; } + internal SvgChartAxis SecondVerticalAxis { get; set; } + internal SvgChartAxis SecondHorizontalAxis { get; set; } + private void SetChartArea() + { + var item = new RenderChartArea(this); + item.Rectangle.Width = Bounds.Width; + item.Rectangle.Height = Bounds.Height; + item.Rectangle.SetDrawingPropertiesFill(Theme, Chart.Fill, Chart.StyleManager.Style.ChartArea.FillReference.Color); + item.Rectangle.SetDrawingPropertiesBorder(Theme, Chart.Border, Chart.StyleManager.Style.ChartArea.BorderReference.Color, Chart.Border.Width > 0); + item.AppendRenderItems(RenderItems); + ChartArea = item; + } + internal List DefItems { get; } = new List(); + internal void AddDefs(RenderItem item) + { + DefItems.Add(item); + } + internal double GetPlotAreaTop() + { + var margin = 14D; + if(Legend!=null && Chart.Legend.Position==eLegendPosition.Top) + { + return Legend.Rectangle.Bottom + margin; + } + else if (Title != null) + { + return Title.Rectangle.Bottom + margin; + } + else + { + return margin; + } + + } + + internal LineRenderItem GetSeriesIcon(ExcelChartStandardSerie s, int index, BoundingBox parentItem) + { + const float MarginExtra = 1.5f; + const float LineLength = 21; + + var item = new LineRenderItem(parentItem); + item.SetDrawingPropertiesFill(Theme, s.Fill, this.Chart.StyleManager.Style.SeriesLine.FillReference.Color); + item.SetDrawingPropertiesBorder(Theme, s.Border, this.Chart.StyleManager.Style.SeriesLine.BorderReference.Color, s.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + float y = (float)parentItem.Top + MarginExtra; + float x = 0; + item.X1 = x; + item.Y1 = y; + item.X2 = x + LineLength; + item.Y2 = y; + item.LineCap = LineCap.Round; + + return item; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSerie.cs b/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSerie.cs new file mode 100644 index 0000000000..f1aea585d8 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSerie.cs @@ -0,0 +1,44 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using System; + +namespace EPPlusImageRenderer.Svg +{ + internal class DrawingLegendSerie : DrawingLegendSeriesIcon + { + internal DrawingTextBody Textbox { get; set; } + + internal void GetIconTopLeft(out double top, out double left) + { + if (SeriesIcon is LineRenderItem line) + { + top = line.Y1; + left = line.X1; + } + else if (SeriesIcon is RectRenderItem rect) + { + top = rect.Top; + left = rect.Left; + } + else + { + top = SeriesIcon.Bounds.Top; + left = SeriesIcon.Bounds.Left; + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSeriesIcon.cs b/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSeriesIcon.cs new file mode 100644 index 0000000000..84ea79dfe7 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/DrawingLegendSeriesIcon.cs @@ -0,0 +1,11 @@ +using EPPlus.DrawingRenderer.RenderItems; + +namespace EPPlusImageRenderer.Svg +{ + internal class DrawingLegendSeriesIcon + { + internal RenderItem SeriesIcon { get; set; } + internal RenderItem MarkerIcon { get; set; } + internal RenderItem MarkerBackground { get; set; } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/LineMarkerHelper.cs b/src/EPPlus/Drawing/Renderer/Chart/LineMarkerHelper.cs new file mode 100644 index 0000000000..42949125f1 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/LineMarkerHelper.cs @@ -0,0 +1,168 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using System; +using System.Collections.Generic; + +namespace OfficeOpenXml.Drawing.Renderer.Chart +{ + internal class LineMarkerHelper + { + internal static RenderItem GetMarkerItem(ChartRenderer sc, ExcelLineChartSerie ls, double x, double y, bool isLegend) + { + RenderItem item; + var m = ls.Marker; + float maxSize = isLegend ? 7f : float.MaxValue; + var size = m.Size > maxSize ? maxSize : m.Size; + var halfSize = size / 2; + var xPath = x; + var yPath = y; + //var halfY = halfSize / sc.ChartArea.Rectangle.Height; + //var halfX = halfSize / sc.ChartArea.Rectangle.Width; + switch (m.Style) + { + case eMarkerStyle.Circle: + item = new EllipseRenderItem(sc.Bounds) + { + Rx = halfSize, + Ry = halfSize, + Cx = x, + Cy = y + }; + break; + case eMarkerStyle.Triangle: + item = new PathRenderItem(sc.Bounds); + var cmd = new PathCommands(PathCommandType.Move, new double[] { xPath + halfSize, yPath + halfSize, xPath, yPath - halfSize, xPath - halfSize, yPath + halfSize }); + ((PathRenderItem)item).Commands.Add(cmd); + ((PathRenderItem)item).Commands.Add(new PathCommands(PathCommandType.End)); + break; + case eMarkerStyle.Diamond: + item = new PathRenderItem(sc.ChartArea.Rectangle.Bounds); + cmd = new PathCommands(PathCommandType.Move, new double[] { (xPath - halfSize), yPath, xPath, yPath + halfSize, xPath + halfSize, yPath, xPath, yPath - halfSize }); + ((PathRenderItem)item).Commands.Add(cmd); + ((PathRenderItem)item).Commands.Add(new PathCommands(PathCommandType.End)); + break; + case eMarkerStyle.Dot: + case eMarkerStyle.Dash: + if (isLegend) + { + item = null; + } + else + { + if(m.Style == eMarkerStyle.Dot) + { + item = new RectRenderItem(sc.Bounds) + { + Left = x, + Top = y - size / 8, + Width = size / 2, + Height = size / 4 + }; + } + else //Dash + { + item = new RectRenderItem(sc.Bounds) + { + Left = x - size / 2, + Top = y - size / 8, + Width = size, + Height = size / 4 + }; + } + } + break; + case eMarkerStyle.Square: + item = new RectRenderItem(sc.Bounds) + { + Left = x - size / 2, + Top = y - size / 2, + Width = size, + Height = size + }; + break; + case eMarkerStyle.Plus: + case eMarkerStyle.Star: + case eMarkerStyle.X: + var pathItem = new PathRenderItem(sc.Bounds); + if (m.Style == eMarkerStyle.Star) + { + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath - halfSize, yPath - halfSize, xPath + halfSize, yPath + halfSize })); + + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath, yPath + halfSize, xPath, yPath - halfSize })); + + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath + halfSize, yPath - halfSize, xPath - halfSize, yPath + halfSize })); + pathItem.Commands.Add(new PathCommands(PathCommandType.End)); + + } + else if (m.Style == eMarkerStyle.X) + { + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath - halfSize, yPath - halfSize, xPath + halfSize, yPath + halfSize })); + pathItem.Commands.Add(new PathCommands(PathCommandType.End)); + + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath - halfSize, yPath + halfSize, xPath + halfSize, yPath - halfSize })); + pathItem.Commands.Add(new PathCommands(PathCommandType.End)); + } + else + { + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath, yPath - halfSize, xPath, yPath + halfSize })); + pathItem.Commands.Add(new PathCommands(PathCommandType.End)); + + pathItem.Commands.Add(new PathCommands(PathCommandType.Move, new double[] { xPath - halfSize, yPath, xPath + halfSize, yPath })); + pathItem.Commands.Add(new PathCommands(PathCommandType.End)); + } + item = pathItem; + break; + default: + item = null; + break; + } + if (ls.Marker.Fill.IsEmpty == false) + { + item?.SetDrawingPropertiesFill(sc.Theme, ls.Marker.Fill, sc.Chart.StyleManager.Style.DataPointMarker.FillReference.Color, false); + } + else if (ls.Fill.IsEmpty) + { + item?.SetDrawingPropertiesFillBasic(sc.Theme, ls.Border.Fill, sc.Chart.StyleManager.Style?.DataPointMarker.FillReference.Color, false, sc.Theme.ColorScheme.Accent1); + } + else + { + item?.SetDrawingPropertiesFill(sc.Theme, ls.Fill, sc.Chart.StyleManager.Style.DataPointMarker.FillReference.Color, false); + } + + if (ls.Marker.Border.Width > 0) + { + if (ls.Marker.Border.Fill.IsEmpty) + { + item?.SetDrawingPropertiesBorder(sc.Theme, ls.Border, sc.Chart.StyleManager.Style.DataPointMarker.BorderReference.Color, ls.Border.Fill.Style != eFillStyle.NoFill, 0.75); + } + else + { + item?.SetDrawingPropertiesBorder(sc.Theme, ls.Marker.Border, sc.Chart.StyleManager.Style.DataPointMarker.BorderReference.Color, ls.Marker.Border.Fill.Style != eFillStyle.NoFill, 0.75); + } + } + return item; + } + internal static RenderItem GetMarkerBackground(ChartRenderer sc, ExcelLineChartSerie ls, double x, double y, bool isLegend) + { + RenderItem item; + var m = ls.Marker; + float maxSize = isLegend ? 7f : float.MaxValue; + var size = m.Size > maxSize ? maxSize : m.Size; + item = new RectRenderItem(sc.Bounds) + { + Left = x - (size / 2), + Top = y - (size / 2), + Width = size, + Height = size + }; + item?.SetDrawingPropertiesFill(sc.Theme, ls.Marker.Fill, sc.Chart.StyleManager.Style.DataPointMarker.FillReference.Color, false); + return item; + } + + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/PieSliceRenderItem.cs b/src/EPPlus/Drawing/Renderer/Chart/PieSliceRenderItem.cs new file mode 100644 index 0000000000..fb58373378 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/PieSliceRenderItem.cs @@ -0,0 +1,585 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Utils.Drawing; +using System; +using System.Collections.Generic; +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + internal class PieSliceRenderItem : ChartDrawingObject + { + double _radius; + /// + /// The holder of transform-origin/translations + /// + GroupRenderItem _innerGroup; + /// + /// The holder of the actual items, AFTER origin/translations + /// + GroupRenderItem _innerItems; + Point _circleCenter; + + /// + /// How many percent of the pie this represents + /// + double _percent; + + internal double Degrees { get; private set; } + + Point _startPoint; + Point _midPoint; + Point _endPoint; + + /// + /// Get copy of start point of slice in local coordinates + /// + /// + internal Coordinate GetStartPointPositionLocal() + { + return new Coordinate(_startPoint.Left, _startPoint.Top); + } + /// + /// Get copy of mid point of slice in local coordinates + /// + /// + internal Coordinate GetMidPointLocal() + { + return new Coordinate(_midPoint.Left, _midPoint.Top); + } + /// + /// Get copy of end point of slice in local coordinates + /// + /// + internal Coordinate GetEndPointLocal() + { + return new Coordinate(_endPoint.LocalPosition.X, _endPoint.LocalPosition.Y); + } + + PathRenderItem _slicePath; + + + List DebugItems; + PathRenderItem _debugBoundsPath; + RectRenderItem _debugCircleCenter; + + bool ExistWithinRange(double target, double min, double max) + { + if (min < target && target < max) + { + return true; + } + return false; + } + + internal BoundingBox ExtremePoints { get; set; } + + void CalculateWidthHeight(double prevSliceDegrees) + { + + var endPointDegrees = prevSliceDegrees + Degrees; + if (endPointDegrees < 0) + { + endPointDegrees = 360 + endPointDegrees; + } + + var startPointDegrees = prevSliceDegrees; + if (startPointDegrees < 0) + { + startPointDegrees = 360 + startPointDegrees; + } + + var circleSectorDegrees = endPointDegrees - startPointDegrees; + + double maxX; + double maxY; + double minY; + double minX; + + if (ExistWithinRange(90, startPointDegrees, endPointDegrees)) + { + maxY = _circleCenter.Top + _radius; + } + else + { + maxY = Math.Max(_startPoint.Top, _endPoint.Top); + } + + maxY = Math.Max(maxY, _circleCenter.Top); + + if (ExistWithinRange(180, startPointDegrees, endPointDegrees)) + { + minX = _circleCenter.Left - _radius; + } + else + { + minX = Math.Min(_startPoint.Left, _endPoint.Left); + } + + minX = Math.Min(minX, _circleCenter.Left); + + if (ExistWithinRange(270, startPointDegrees, endPointDegrees)) + { + minY = _circleCenter.Top - _radius; + } + else + { + minY = Math.Min(_startPoint.Top, _endPoint.Top); + } + + minY = Math.Min(minY, _circleCenter.Top); + + if (endPointDegrees < startPointDegrees || ExistWithinRange(0, startPointDegrees, endPointDegrees)) + { + if (endPointDegrees > 270) + { + maxX = _circleCenter.Left; + } + else + { + maxX = _circleCenter.Left + _radius; + } + } + else + { + maxX = Math.Max(_startPoint.Left, _endPoint.Left); + } + + maxX = Math.Max(_circleCenter.Left, maxX); + + + ExtremePoints = new BoundingBox(minX, minY, maxX - minX, maxY - minY); + ExtremePoints.Parent = _innerGroup.Bounds; + } + + private double _sliceScaleFactor = 1d; + private double _scaledRadius { get { return _radius * _sliceScaleFactor; } } + + + private void CalculateExplosionDir() + { + var transformOriginLocal = new Vector2(_innerGroup.TransformOrigin.X, _innerGroup.TransformOrigin.Y); + + //Get directional vector (in local coords but does not matter since we make it directional) + Vector2 pieDirection = transformOriginLocal - _circleCenter.LocalPosition; + + //normalize the pieDirection vector so that it is percentual and with lenght == 1 + pieDirection = pieDirection / pieDirection.Length; + + CtrToOuterMidDir = new Vector2(pieDirection.X, pieDirection.Y); + } + + public PieSliceRenderItem(ChartRenderer renderer, BoundingBox parent, Point circleCenter, double radius, double percentOfPie, double prevSliceDegrees) : base(renderer) + { + Rectangle.Bounds.Parent = parent; + _radius = radius; + _percent = percentOfPie; + //How many degrees that percentage is out of 360 + Degrees = _percent * 360d; + + _innerGroup = new GroupRenderItem(parent, 0, circleCenter); + _innerGroup.Bounds.Parent = _innerGroup.TranslationOffset; + _innerGroup.Bounds.Name = "InnerGroupChartDrawer"; + + _circleCenter = circleCenter; + + _startPoint = CalculateLocalPointOnCircle(prevSliceDegrees); + + //The degrees of the midpoint + var halfDegrees = Degrees / 2; + + _endPoint = CalculateLocalPointOnCircle(Degrees + prevSliceDegrees); + + //We add prev at this point since we don't want to halve the previous angle only the current one + _midPoint = CalculateLocalPointOnCircle(halfDegrees + prevSliceDegrees); + + //We must calculate transforms from the outer midpoint. + //This is to ensure that point never leaves the parent container + _innerGroup.TransformOrigin = GetMidPointLocal(); + + CalculateExplosionDir(); + CalculateWidthHeight(prevSliceDegrees); + + + _innerItems = new GroupRenderItem(_innerGroup.Bounds, 0); + } + + internal void ImportPathData(BoundingBox plotAreaBounds, BoundingBox globalAreaBounds, double sliceScaleFactor, double explosionOfPoint, double pieExplosion, int position) + { + _slicePath = new PathRenderItem(plotAreaBounds); + + _slicePath.BorderWidth = 5; + + //Calculate path commands + var moveCenter = new PathCommands(PathCommandType.Move, _circleCenter.Left, _circleCenter.Top); + var lineToStart = new PathCommands(PathCommandType.Line, _startPoint.Left, _startPoint.Top); + + var arcCommand = new PathCommands(PathCommandType.Arc, new double[] { _radius, _radius, 0, Degrees > 180 ? 1 : 0, 1, _endPoint.Left, _endPoint.Top }); + var end = new PathCommands(PathCommandType.End, _endPoint.Left, _endPoint.Top); + + //Get max and min values + var localMax = GetTranslationMaxLocal(globalAreaBounds.Width, globalAreaBounds.Height); + var localMin = GetTranslationMinLocal(globalAreaBounds.Width, globalAreaBounds.Height); + + _sliceScaleFactor = sliceScaleFactor; + //Translate and scale path + _innerGroup.Scale = new Coordinate(_sliceScaleFactor, _sliceScaleFactor); + CalculatePointExplosion(explosionOfPoint, pieExplosion, localMax, localMin); + + //Add the actual commands + _slicePath.Commands.Add(moveCenter); + _slicePath.Commands.Add(lineToStart); + _slicePath.Commands.Add(arcCommand); + + //Change to != -1 to activate debug items + if (position == -1) + { + //Visualize all points + AddDebugLines(moveCenter, plotAreaBounds); + } + + _slicePath.Commands.Add(end); + + } + + /// + /// Adds line from center to outer mid point (transform-origin) and to end point + /// AKA line along scale/explosion vector + /// + /// + private void AddDebugLines(PathCommands moveCenter, BoundingBox bounds) + { + DebugItems = new List(); + + //Render bounds for slice + _debugBoundsPath = new PathRenderItem(bounds); + _debugBoundsPath.BorderColor = "red"; + _debugBoundsPath.FillColor = "transparent"; + _debugBoundsPath.BorderWidth = 3; + var moveCenterDebug = new PathCommands(PathCommandType.Move, ExtremePoints.Left, ExtremePoints.Top); + _debugBoundsPath.Commands.Add(moveCenterDebug); + + //Draw extremes/bounds + //var lineToTopLeft = new PathCommands(PathCommandType.Line, ExtremePoints.Left, ExtremePoints.Top); + var lineToTopRight = new PathCommands(PathCommandType.Line, ExtremePoints.Right, ExtremePoints.Top); + + var lineToBottomRight = new PathCommands(PathCommandType.Line, ExtremePoints.Right, ExtremePoints.Bottom); + var lineToBottomLeft = new PathCommands(PathCommandType.Line, ExtremePoints.Left, ExtremePoints.Bottom); + var end = new PathCommands(PathCommandType.End, ExtremePoints.Left, ExtremePoints.Top); + + _debugBoundsPath.Commands.Add(lineToTopRight); + _debugBoundsPath.Commands.Add(lineToBottomRight); + _debugBoundsPath.Commands.Add(lineToBottomLeft); + _debugBoundsPath.Commands.Add(end); + + DebugItems.Add(_debugBoundsPath); + + //Render green dot at circle center + _debugCircleCenter = GenerateDebugPoint(bounds, new Coordinate(_circleCenter.Left, _circleCenter.Top), "green"); + + DebugItems.Add(_debugCircleCenter); + + //render dots at points + var pointColor = "yellow"; + + var startDebug = GenerateDebugPoint(bounds, GetStartPointPositionLocal(), pointColor); + var midDebug = GenerateDebugPoint(bounds, GetMidPointLocal(), pointColor); + var endDebug = GenerateDebugPoint(bounds, GetEndPointLocal(), pointColor); + + DebugItems.Add(startDebug); + DebugItems.Add(midDebug); + DebugItems.Add(endDebug); + } + + private RectRenderItem GenerateDebugPoint(BoundingBox parent, Coordinate point, string fillColor) + { + double l = -2.5d; + double t = -2.5d; + double w = 5d; + double h = 5d; + + return new RectRenderItem(parent) { Left = l + point.X, Top = t + point.Y, Width = w, Height = h, FillColor = fillColor }; + } + + + internal void ImportStlyeInfo(ExcelChartDataPoint dp, ExcelPieChart chartType) + { + _slicePath.SetDrawingPropertiesFill(ChartRenderer.Theme, dp.Fill, chartType.StyleManager.Style.DataPoint.FillReference.Color); + _slicePath.SetDrawingPropertiesBorder(ChartRenderer.Theme, dp.Border, chartType.StyleManager.Style.DataPoint.BorderReference.Color, true); + _slicePath.SetDrawingPropertiesEffects(ChartRenderer.Theme, dp.Effect); + } + + internal void AppendGroupItem(GroupRenderItem group) + { + //Apply translation after all calculations are done + _innerGroup.Left += _innerGroup.TranslationOffset.Left; + _innerGroup.Top += _innerGroup.TranslationOffset.Top; + + //The slice items post transform operations + _innerItems.AddChildItem(_slicePath); + //The bounds and translations of the slice + _innerGroup.AddChildItem(_innerItems); + + if (DebugItems != null && DebugItems.Count > 0) + { + foreach(var debugItem in DebugItems) + { + _innerGroup.AddChildItem(debugItem); + } + } + + //The group containing all slices + group.AddChildItem(_innerGroup); + } + + Vector2 GetTranslationMaxLocal(double globalWidth, double globalHeight) + { + var worldPositionTransformOrigin = _midPoint.Position; + + //Calculate extremes + Point localMax = new Point( + globalWidth - worldPositionTransformOrigin.X, + globalHeight - worldPositionTransformOrigin.Y); + + return localMax.LocalPosition; + } + + Vector2 GetTranslationMinLocal(double globalWidth, double globalHeight) + { + var worldPositionTransformOrigin = _midPoint.Position; + //Calculate extremes + Point worldMin = new Point(-worldPositionTransformOrigin.X, -worldPositionTransformOrigin.Y); + + //var localMin = _innerGroup.Position.Parent.TransformPointToLocal(worldMin.Position); + return worldMin.LocalPosition; + } + + /// + /// The directional vector from center of circle to the outer midpoint of the pie slice + /// + internal Vector2 CtrToOuterMidDir { get; private set; } + + /// + /// Gets the whole vector with length to the end + /// + /// + internal Vector2 GetWholeVectorCenterToMid() + { + var translationVector = GetLocalTranslationVector(100); + var pt = translationVector; + return pt; + } + + /// + /// + /// + /// + internal Point GetSliceShapeCenterLocal() + { + var translationVector = GetLocalTranslationVector(50); + var pt = _circleCenter.LocalPosition + translationVector; + var SliceCenterLocal = new Point(pt.X, pt.Y); + + return SliceCenterLocal; + } + /// + /// Input must be between 0 and 100 + /// + /// + /// + Vector2 GetLocalTranslationVector(double percentTowardsEndPoint) + { + if (percentTowardsEndPoint < 0 || percentTowardsEndPoint > 100) + { + throw new InvalidOperationException($"input: '{percentTowardsEndPoint}' invalid. Must be between 0 and 100"); + } + + var moveFactor = (double)percentTowardsEndPoint / 100d; + var moveFactoredDirection = moveFactor * CtrToOuterMidDir; + + //Get distance/length to move along vector. We translate according to the scaled down radius + Vector2 LocalTranslationVector = moveFactoredDirection * _scaledRadius; + return LocalTranslationVector; + } + + Vector2 GetLocalTranslationVector(double explosionOfPoint, double pieExplosion) + { + //Get point explosion value + var pointExplosion = explosionOfPoint == int.MinValue ? 0 : explosionOfPoint; + + var pieDirection = new Vector2(CtrToOuterMidDir.X, CtrToOuterMidDir.Y); + + if (pointExplosion != 0 && pointExplosion < pieExplosion) + { + //Direction is inward rather than outward + pieDirection = (pieDirection * -1); + } + else if (pieExplosion != 0 && pointExplosion > pieExplosion) + { + //Scaling has already translated the slice partially. + //Remove that from the translation percent + pointExplosion -= pieExplosion; + } + + var ptExplodeFactor = (double)pointExplosion / 100d; + var ptFactoredDirection = ptExplodeFactor * pieDirection; + + //Get distance/length to move along vector. We translate according to the scaled down radius + Vector2 LocalTranslationVector = ptFactoredDirection * _scaledRadius; + return LocalTranslationVector; + } + + Coordinate GetFinalLocalTranslation(Vector2 LocalTranslationVector, Vector2 localMax, Vector2 localMin) + { + Coordinate lengthPoint = new Coordinate(0, 0); + + //Check if local is above or below extremes in X axis + if (LocalTranslationVector.X != 0) + { + if (LocalTranslationVector.X > 0 && LocalTranslationVector.X > localMax.X) + { + lengthPoint.X = localMax.X; + } + else if (LocalTranslationVector.X < localMin.X) + { + lengthPoint.X = Math.Abs(localMin.X); + } + } + + //Check if local is above or below extremes in Y axis + if (LocalTranslationVector.Y != 0) + { + if (LocalTranslationVector.Y > 0 && LocalTranslationVector.Y > localMax.Y) + { + lengthPoint.Y = localMax.Y; + } + else if (LocalTranslationVector.Y < localMin.Y) + { + lengthPoint.Y = Math.Abs(localMin.Y); + } + } + + //Find the smallest length of a vector that goes beyond the extremes + //In case both do + var maxAllowedLength = Math.Min(lengthPoint.X, lengthPoint.Y); + if (maxAllowedLength == 0) + { + //Avoid issues if one axis is 0 and the vector that goes over is positive + maxAllowedLength = Math.Max(lengthPoint.X, lengthPoint.Y); + } + + double translationLeft; + double translationTop; + + if (maxAllowedLength != 0 && maxAllowedLength < LocalTranslationVector.Length) + { + //If the length is larger than maximum allowed length we stop applying translation + var normalizedVector = LocalTranslationVector / LocalTranslationVector.Length; + var appliedVector = normalizedVector * maxAllowedLength; + + translationLeft = appliedVector.X; + translationTop = appliedVector.Y; + } + else + { + //The length is within the bounds. No binding neccesary. + translationLeft = LocalTranslationVector.X; + translationTop = LocalTranslationVector.Y; + } + + return new Coordinate(translationLeft, translationTop); + } + + void CalculatePointExplosion(double explosionOfPoint, double pieExplosion, Vector2 localMax,Vector2 localMin) + { + //Get distance/length to move along vector + Vector2 LocalTranslationVector = GetLocalTranslationVector(explosionOfPoint, pieExplosion); + var finalTranslation = GetFinalLocalTranslation(LocalTranslationVector, localMax, localMin); + + _innerGroup.TranslationOffset.Left = finalTranslation.X; + _innerGroup.TranslationOffset.Top = finalTranslation.Y; + } + + Point CalculateLocalPointOnCircle(double degrees) + { + var angleRadians = MConverter.DegreesToRadians(degrees); + + var xPoint = _circleCenter.Left + (_radius * Math.Cos(angleRadians)); + var yPoint = _circleCenter.Top + (_radius * Math.Sin(angleRadians)); + + var point = new Point(); + + //Ensure the cx/cy offset + point.Parent = _innerGroup.TranslationOffset.Parent; + point.Left = xPoint; + point.Top = yPoint; + + return point; + } + + internal Coordinate GetOuterMidpointInGlobalCoords() + { + return new Coordinate(_midPoint.Position.X, _midPoint.Position.Y); + } + + + internal Transform CopyOuterMidPoint() + { + var transform = new Transform(); + transform.Parent = _midPoint.Parent; + transform.Position = transform.Position + _midPoint.LocalPosition; + return transform; + } + + internal Transform CopyStartPoint() + { + var translationVector = GetLocalTranslationVector(100); + var transform = new Transform(); + transform.Parent = _midPoint.Parent; + transform.Position = transform.Position + _midPoint.LocalPosition; + return transform; + } + + internal GroupRenderItem GetInnerItemGroup() + { + return _innerGroup; + } + + /// + /// Transform origin in local coordinates + /// Translated + /// + /// + internal Coordinate GetInnerGroupTransformOriginTranslated() + { + return new Coordinate(_innerGroup.TransformOrigin.X + _innerGroup.TranslationOffset.Left, _innerGroup.TransformOrigin.Y + _innerGroup.TranslationOffset.Top); + } + /// + /// Transform origin in local coordinates + /// Translated + /// + /// + internal Transform GetInnerGroupWithTransformOriginTranslated() + { + Transform transform = new Transform(); + transform.Parent = _innerGroup.Bounds.Parent; + transform.LocalPosition += new Vector2(_innerGroup.TransformOrigin.X + _innerGroup.TranslationOffset.Left, _innerGroup.TransformOrigin.Y + _innerGroup.TranslationOffset.Top); + return transform; + } + + public override void AppendRenderItems(List renderItems) + { + + throw new NotImplementedException(); + } + + //internal BoundingBox GetInnerGroupBounds() + //{ + // return _innerGroup.Bounds; + //} + } +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/SvgChartLegendIcon.cs b/src/EPPlus/Drawing/Renderer/Chart/SvgChartLegendIcon.cs new file mode 100644 index 0000000000..e9af389514 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/SvgChartLegendIcon.cs @@ -0,0 +1,117 @@ +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Interfaces.Drawing.Text; +using System; +using System.Collections.Generic; + +namespace EPPlus.Export.ImageRenderer.Svg.Chart +{ + //internal class SvgChartLegendIcon : SvgRenderLineItem + //{ + // const float MarginExtra = 1.5f; + // const float MiddleMargin = 7.5f; + // const float LineLength = 21; + + // public SvgChartLegendIcon(DrawingChart sc, SvgRenderRectItem Rectangle, ExcelChartStandardSerie s, TextMeasurement tm, double topMargin, double leftMargin, TextMeasurement sHM, SvgLegendSerie pSls) : base(sc, Rectangle.Bounds) + // { + // SetDrawingPropertiesFill(s.Fill, sc.Chart.StyleManager.Style.SeriesLine.FillReference.Color); + // SetDrawingPropertiesBorder(s.Border, sc.Chart.StyleManager.Style.SeriesLine.BorderReference.Color, s.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + // if (sc.Chart.Legend.Position == eLegendPosition.Top || + // sc.Chart.Legend.Position == eLegendPosition.Bottom) + // { + // float y = (float)Rectangle.Top + (float)topMargin + tm.Height / 2 + MarginExtra; + // float x = 0; + // if (pSls == null) + // { + // x = (float)Rectangle.Left + (float)leftMargin;// + MarginIconText; + // } + // else + // { + // x = (float)pSls.Textbox.Bounds.Right + MiddleMargin; + // } + + // X1 = x; + // Y1 = y; + // X2 = x + LineLength; + // Y2 = y; + // LineCap = eLineCap.Round; + // } + // else + // { + // double y; + // if (pSls == null) + // { + // y = topMargin + tm.Height / 2 + MarginExtra; + // } + // else + // { + // var pTm = sHM; + // y = ((SvgRenderLineItem)pSls.SeriesIcon).Y1 + pTm.Height / 2 + tm.Height / 2 + MiddleMargin; + // } + + // X1 = (float)leftMargin; //4 + // Y1 = y; + // X2 = (float)LineLength; + // Y2 = y; + // LineCap = eLineCap.Round; + // } + // } + + // //internal override void AppendRenderItems(List renderItems) + // //{ + // // throw new NotImplementedException(); + // //} + + // //private SvgRenderLineItem GetLineSeriesIcon(DrawingChart sc, ExcelChartStandardSerie s, TextMeasurement sHM, TextMeasurement tm, SvgLegendSerie pSls) + // //{ + // // var item = new SvgRenderLineItem(sc, Rectangle.Bounds); + // // item.SetDrawingPropertiesFill(s.Fill, sc.Chart.StyleManager.Style.SeriesLine.FillReference.Color); + // // item.SetDrawingPropertiesBorder(s.Border, sc.Chart.StyleManager.Style.SeriesLine.BorderReference.Color, s.Border.Fill.Style != eFillStyle.NoFill, 0.75); + + // // if (sc.Chart.Legend.Position == eLegendPosition.Top || + // // sc.Chart.Legend.Position == eLegendPosition.Bottom) + // // { + // // float y = (float)Rectangle.Top + (float)TopMargin + tm.Height / 2 + MarginIconText; + // // float x = 0; + // // if (pSls == null) + // // { + // // x = (float)Rectangle.Left + (float)LeftMargin;// + MarginIconText; + // // } + // // else + // // { + // // x = (float)pSls.Textbox.Bounds.Right + MarginHeight; + // // } + + // // item.X1 = x; + // // item.Y1 = y; + // // item.X2 = x + LineLength; + // // item.Y2 = y; + // // item.LineCap = eLineCap.Round; + // // } + // // else + // // { + // // double y; + // // if (pSls == null) + // // { + // // y = TopMargin + tm.Height / 2 + MarginIconText; + // // } + // // else + // // { + // // var pTm = sHM; + // // y = ((SvgRenderLineItem)pSls.SeriesIcon).Y1 + pTm.Height / 2 + tm.Height / 2 + MarginHeight; + // // } + + // // item.X1 = (float)LeftMargin; //4 + // // item.Y1 = y; + // // item.X2 = (float)LineLength; + // // item.Y2 = y; + // // item.LineCap = eLineCap.Round; + // // } + + // // return item; + // //} + //} +} diff --git a/src/EPPlus/Drawing/Renderer/Chart/eTextOrientation.cs b/src/EPPlus/Drawing/Renderer/Chart/eTextOrientation.cs new file mode 100644 index 0000000000..8677f954b9 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Chart/eTextOrientation.cs @@ -0,0 +1,21 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace EPPlus.Export.Renderer +{ + internal enum eTextOrientation + { + Horizontal, + Diagonal, + Vertical, + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/ChartRenderer.cs b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs new file mode 100644 index 0000000000..194e4b6317 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs @@ -0,0 +1,418 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Export.ImageRenderer.Svg.Chart; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using System; +using System.Collections.Generic; +using System.Text; +using d=OfficeOpenXml.Drawing.Renderer; +namespace EPPlusImageRenderer +{ + internal class ChartRenderer : d.DrawingRenderer + { + public ChartRenderer(ExcelChart chart, SvgRenderOptions options) : base(chart) + { + SetChartArea(options); + + if (chart.HasTitle && chart.Series.Count > 0) + { + Title = new ChartTitleRenderer(this, (ExcelChartTitleStandard)chart.Title, "Chart Title"); + } + else + { + Title = null; + } + + //We need to create the plotarea before the legend and axes, as the trendlines can affect the value axis and should be rendererd in the legend. + Plotarea = new ChartPlotareaRenderer(this); + Plotarea.ChartTypeDrawers = ChartTypeDrawer.Create(this); + + if (chart.HasLegend) + { + Legend = new ChartLegendRenderer(this); + } + else + { + Legend = null; + } + + if (Chart.Axis.Length != 0) + { + HorizontalAxis = GetAxis(false); + VerticalAxis = GetAxis(true); + } + + if (chart.Axis.Length > 2) + { + SecondVerticalAxis = GetAxis(true, 2); + SecondHorizontalAxis = GetAxis(false, 2); + } + + Plotarea.SetPlotAreaRectangle(); + + //As we need the plotarea dimensions to calculate the axis positions we need to set the axis positions after creating the plotarea. + SetAxisPositionsFromPlotarea(); + + Plotarea.DrawSeries(); + + //Append all renderitems after everything has been created and positioned, to ensure the correct z-ordering. + AppendItems(); + + } + private void SetAxisPositionsFromPlotarea() + { + if (VerticalAxis != null) + { + PlaceVerticalAxis(VerticalAxis); + //Make sure the horizontal axis is moved up if the vertical axis has a negative minimum value, so that the 0 value is at the correct position. + if (VerticalAxis.Axis.TickLabelPosition == eTickLabelPosition.NextTo && HorizontalAxis.Axis.AxisType == eAxisType.Val && HorizontalAxis.Min < 0D) + { + Plotarea.Rectangle.Width += VerticalAxis.Rectangle.Width; + Plotarea.Group.Left = VerticalAxis.Rectangle.Left; + var newRight = Plotarea.Group.Left + HorizontalAxis.GetPositionInPlotarea(0D); + var rightDiff = newRight - VerticalAxis.Rectangle.Width; + VerticalAxis.Rectangle.Left = rightDiff; + VerticalAxis.Line.X1 = VerticalAxis.Line.X2 = newRight; + } + VerticalAxis.AddTickmarksAndValues(DefItems); + } + + if (HorizontalAxis != null && HorizontalAxis.Rectangle != null) + { + PlaceHorizontalAxis(HorizontalAxis, false); + + //Make sure the horizontal axis is moved up if the vertical axis has a negative minimum value, so that the 0 value is at the correct position. + if (HorizontalAxis.Axis.TickLabelPosition == eTickLabelPosition.NextTo && VerticalAxis.Axis.AxisType == eAxisType.Val && VerticalAxis.Min < 0D) + { + var newtop = VerticalAxis.GetPositionInPlotarea(0D) + Plotarea.Group.Top; + var topDiff = HorizontalAxis.Rectangle.Top - newtop; + HorizontalAxis.Rectangle.Top = newtop; + HorizontalAxis.Rectangle.Height += topDiff; + HorizontalAxis.Line.Y1 = HorizontalAxis.Line.Y2 = newtop; + } + + HorizontalAxis.AddTickmarksAndValues(DefItems); + } + + if (SecondVerticalAxis != null) + { + PlaceVerticalAxis(SecondVerticalAxis); + SecondVerticalAxis.AddTickmarksAndValues(DefItems); + } + + if (SecondHorizontalAxis != null && SecondHorizontalAxis.Rectangle != null) + { + PlaceHorizontalAxis(SecondHorizontalAxis, true); + SecondHorizontalAxis.AddTickmarksAndValues(DefItems); + } + } + + private void PlaceHorizontalAxis(ChartAxisRenderer horizontalAxis, bool isSecondary) + { + if (horizontalAxis.Axis.Deleted == false) + { + horizontalAxis.Rectangle.Width = Plotarea.Rectangle.Width; + horizontalAxis.Rectangle.Left = Plotarea.Group.Left; + horizontalAxis.Line.X1 = (float)horizontalAxis.Rectangle.Left; + horizontalAxis.Line.X2 = (float)horizontalAxis.Rectangle.Right; + + var axisPos = horizontalAxis.Axis.ActualAxisPosition; + if (axisPos == eActualAxisPosition.Bottom) + { + horizontalAxis.Rectangle.Top = Plotarea.Group.Top + Plotarea.Rectangle.Height; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = (float)Plotarea.Group.Top + Plotarea.Rectangle.Height; + } + else if(axisPos == eActualAxisPosition.BottomSecond) + { + horizontalAxis.Rectangle.Top = Plotarea.Group.Top + Plotarea.Rectangle.Height + HorizontalAxis.Rectangle.Height; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = horizontalAxis.Rectangle.Top; + } + else if(axisPos == eActualAxisPosition.Top) + { + horizontalAxis.Rectangle.Top = Plotarea.Group.Top - horizontalAxis.Rectangle.Height; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = (float)Plotarea.Group.Top; + } + else + { + horizontalAxis.Rectangle.Top = Plotarea.Group.Top - horizontalAxis.Rectangle.Height - HorizontalAxis.Rectangle.Height; + horizontalAxis.Line.Y1 = horizontalAxis.Line.Y2 = horizontalAxis.Rectangle.Bottom; + } + } + if (horizontalAxis.Title != null) + { + PlaceHorizontalAxisTitle(horizontalAxis); + } + } + + private void PlaceHorizontalAxisTitle(ChartAxisRenderer horizontalAxis) + { + horizontalAxis.Title.Rectangle.Height = Bounds.Height / 4; + horizontalAxis.Title.Rectangle.Width = horizontalAxis.Rectangle?.Width ?? Plotarea.Rectangle.Width; + if (horizontalAxis.Axis.Deleted) + { + if (horizontalAxis.Axis.AxisPosition == eAxisPosition.Bottom) + { + horizontalAxis.Title.TextBox.Top = Plotarea.Group.Top + Plotarea.Rectangle.Height; + } + else + { + horizontalAxis.Title.TextBox.Top = Plotarea.Group.Top - horizontalAxis.Rectangle.Height; + } + } + else + { + if (horizontalAxis.Axis.AxisPosition == eAxisPosition.Bottom) + { + if (SecondHorizontalAxis != null && SecondHorizontalAxis.Axis.ActualAxisPosition == eActualAxisPosition.BottomSecond) + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Bottom + SecondHorizontalAxis.Rectangle.Height; + } + else if (horizontalAxis.Axis.ActualAxisPosition == eActualAxisPosition.Bottom) + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Bottom; + } + else + { + if (Legend != null && Chart.Legend.Position == eLegendPosition.Top) + { + horizontalAxis.Title.TextBox.Top = Legend.Rectangle.Top - horizontalAxis.Title.Rectangle.Height; + } + else + { + horizontalAxis.Title.TextBox.Top = ChartArea.Rectangle.Bottom - horizontalAxis.Title.Rectangle.Height - ChartArea.BottomMargin; + } + } + } + else + { + if (SecondHorizontalAxis.Axis.ActualAxisPosition == eActualAxisPosition.TopSecond) + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Top - SecondHorizontalAxis.Rectangle.Height - horizontalAxis.Title.TextBox.Height; + } + else if (horizontalAxis.Axis.ActualAxisPosition == eActualAxisPosition.Top) + { + horizontalAxis.Title.TextBox.Top = horizontalAxis.Rectangle.Top - horizontalAxis.Title.TextBox.Height; + } + else + { + if (Legend != null && Chart.Legend.Position == eLegendPosition.Top) + { + horizontalAxis.Title.TextBox.Top = Legend.Rectangle.Bottom; + } + else if (Title != null) + { + horizontalAxis.Title.TextBox.Top = Title.Rectangle.Bottom; + } + else + { + horizontalAxis.Title.TextBox.Top = ChartArea.TopMargin; + } + } + } + } + horizontalAxis.Title.TextBox.Left = Plotarea.Group.Left + (Plotarea.Rectangle.Width / 2) - (horizontalAxis.Title.TextBox.Width / 2); + } + + private void PlaceVerticalAxis(ChartAxisRenderer verticalAxis) + { + if (verticalAxis.Axis.Deleted == false && verticalAxis.Rectangle != null) + { + verticalAxis.Rectangle.Top = Plotarea.Group.Top; + verticalAxis.Rectangle.Height = Plotarea.Rectangle.Height; + verticalAxis.Line.Y1 = (float)verticalAxis.Rectangle.Top; + verticalAxis.Line.Y2 = (float)verticalAxis.Rectangle.Bottom; + var axisPos = verticalAxis.Axis.ActualAxisPosition; + + if (axisPos == eActualAxisPosition.Left) + { + verticalAxis.Rectangle.Left = Plotarea.Group.Left - verticalAxis.Rectangle.Width; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Group.Left; + } + else if (axisPos == eActualAxisPosition.LeftSecond) + { + verticalAxis.Rectangle.Left = Plotarea.Group.Left - verticalAxis.Rectangle.Width - VerticalAxis.Rectangle.Width; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Group.Left; + } + else if (axisPos == eActualAxisPosition.Right) + { + verticalAxis.Rectangle.Left = Plotarea.Group.Left + Plotarea.Rectangle.Width; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Group.Left + Plotarea.Rectangle.Width; + } + else + { + verticalAxis.Rectangle.Left = Plotarea.Group.Left + Plotarea.Rectangle.Width + VerticalAxis.Rectangle.Width; + verticalAxis.Line.X1 = verticalAxis.Line.X2 = (float)Plotarea.Group.Left + Plotarea.Rectangle.Width; + } + } + + PlaceVerticalAxisTitle(verticalAxis); + } + + private void PlaceVerticalAxisTitle(ChartAxisRenderer verticalAxis) + { + if (verticalAxis.Title != null) + { + var sinRot = Math.Abs(Math.Sin(MathHelper.Radians(verticalAxis.Title.TextBox.Rotation))); + var cosRot = Math.Abs(Math.Cos(MathHelper.Radians(verticalAxis.Title.TextBox.Rotation))); + verticalAxis.Title.TextBox.Top = Plotarea.Group.Top + (Plotarea.Rectangle.Height / 2) + ((verticalAxis.Title.TextBox.Height * cosRot + verticalAxis.Title.TextBox.Width * sinRot) / 2); + + if (verticalAxis.Axis.AxisPosition == eAxisPosition.Left) + { + if (verticalAxis.Rectangle == null) + { + verticalAxis.Title.TextBox.Left = Plotarea.Group.Left - verticalAxis.Title.TextBox.GetActualWidth() - 1.5; + } + else + { + verticalAxis.Title.TextBox.Left = Plotarea.Group.Left - verticalAxis.Rectangle.Width - verticalAxis.Title.TextBox.GetActualWidth() - 1.5; + } + } + else + { + if (verticalAxis.Rectangle == null) + { + verticalAxis.Title.TextBox.Left = Plotarea.Group.Left + Plotarea.Rectangle.Width; + } + else + { + verticalAxis.Title.TextBox.Left = verticalAxis.Rectangle.Right; + } + } + } + } + + private void SetChartArea(SvgRenderOptions options) + { + var item = new ChartAreaRenderer(this, options); + item.Rectangle.Width = Bounds.Width; + item.Rectangle.Height = Bounds.Height; + + item.Rectangle.SetDrawingPropertiesFill(Theme, Chart.Fill, Chart.StyleManager.Style?.ChartArea.FillReference.Color, true, Theme.ColorScheme.GetColorByEnum(eSchemeColor.Background1)); + item.Rectangle.SetDrawingPropertiesBorder(Theme, Chart.Border, Chart.StyleManager.Style?.ChartArea.BorderReference.Color, Chart.Border.Width > 0); + item.AppendRenderItems(RenderItems); + item.SetMargins(Chart.TextBody); + ChartArea = item; + } + private ChartAxisRenderer GetAxis(bool vertical, int offset = 0) + { + var axis = (ExcelChartAxisStandard)Chart.Axis[offset]; + if (axis.IsVertical == vertical) + { + return new ChartAxisRenderer(this, axis); + } + else if (Chart.Axis.Length > offset + 1) + { + axis = (ExcelChartAxisStandard)Chart.Axis[offset + 1]; + if (axis.IsVertical == vertical) + { + return new ChartAxisRenderer(this, axis); + } + } + return null; + } + + public ExcelChart Chart + { + get =>(ExcelChart)Drawing; + } + internal ChartDrawingObject ChartArea { get; set; } + internal ChartLegendRenderer Legend { get; set; } + internal ChartTitleRenderer Title { get; set; } + internal ChartPlotareaRenderer Plotarea { get; set; } + internal ChartAxisRenderer VerticalAxis { get; set; } + internal ChartAxisRenderer HorizontalAxis { get; set; } + internal ChartAxisRenderer SecondVerticalAxis { get; set; } + internal ChartAxisRenderer SecondHorizontalAxis { get; set; } + + internal List DefItems { get; } = new List(); + internal void AddDefs(RenderItem item) + { + DefItems.Add(item); + } + public bool AppendItems() + { + Plotarea?.AppendRenderItems(RenderItems); + + HorizontalAxis?.AppendRenderItems(RenderItems); + VerticalAxis?.AppendRenderItems(RenderItems); + SecondHorizontalAxis?.AppendRenderItems(RenderItems); + SecondVerticalAxis?.AppendRenderItems(RenderItems); + + if (Plotarea != null) + { + foreach (var drawer in Plotarea?.ChartTypeDrawers) + { + drawer.AppendRenderItems(RenderItems); + } + } + + HorizontalAxis?.Textboxes?.AppendRenderItems(RenderItems); + VerticalAxis?.Textboxes?.AppendRenderItems(RenderItems); + SecondHorizontalAxis?.Textboxes?.AppendRenderItems(RenderItems); + SecondVerticalAxis?.Textboxes?.AppendRenderItems(RenderItems); + + Title?.AppendRenderItems(RenderItems); + Legend?.AppendRenderItems(RenderItems); + + return true; + } + internal double GetPlotAreaTop() + { + var margin = 14D; + if (Legend != null && Chart.Legend.Position == eLegendPosition.Top) + { + return Legend.Rectangle.Bottom + margin; + } + else if (Title != null) + { + return Title.Rectangle.Bottom + margin; + } + else + { + return margin; + } + + } + internal LineRenderItem GetSeriesIcon(ExcelChartStandardSerie s, int index, BoundingBox parentItem) + { + const float MarginExtra = 1.5f; + const float LineLength = 21; + + var item = new LineRenderItem(parentItem); + item.SetDrawingPropertiesFill(Theme, s.Fill, Chart.StyleManager.Style.SeriesLine.FillReference.Color, false); + item.SetDrawingPropertiesBorder(Theme, s.Border, Chart.StyleManager.Style.SeriesLine.BorderReference.Color, s.Border.Fill.Style != eFillStyle.NoFill, 0.75, false); + + float y = (float)parentItem.Top + MarginExtra; + float x = 0; + item.X1 = x; + item.Y1 = y; + item.X2 = x + LineLength; + item.Y2 = y; + item.LineCap = LineCap.Round; + + return item; + } + + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/DefinitionGroup.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/DefinitionGroup.cs new file mode 100644 index 0000000000..e4301600f2 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/DefinitionGroup.cs @@ -0,0 +1,32 @@ +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + internal class DefinitionGroup : RenderItem + { + internal List Items = new List(); + + public DefinitionGroup(DrawingBase renderer) : base(renderer) + { + } + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append(""); + + foreach(var item in Items) + { + item.Render(sb); + } + + sb.Append(""); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinePattern.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinePattern.cs new file mode 100644 index 0000000000..460ff8c80c --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinePattern.cs @@ -0,0 +1,76 @@ +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Style; +using OfficeOpenXml.Utils; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + enum LinePatternType + { + Vertical, + Horizontal + } + + internal class LinePattern : PatternItem + { + LinePatternType type; + + internal SvgRenderLineItem LineItem; + + public LinePattern(DrawingBase baseRend, string id, LinePatternType linesType) : base(baseRend, id) + { + type = linesType; + LineItem = new SvgRenderLineItem(baseRend, Bounds); + + LineItem.BorderWidth = 2; + LineItem.Suffix = "%"; + + LineItem.BorderColor = "#" + Color.DarkGoldenrod.ToColorString(); + + switch (type) + { + case LinePatternType.Vertical: + LineItem.X1 = 0; LineItem.X2 = 0; LineItem.Y1 = 0; LineItem.Y2 = 100; + break; + case LinePatternType.Horizontal: + LineItem.X1 = 0; LineItem.X2 = 100; LineItem.Y1 = 0; LineItem.Y2 = 0; + break; + } + + SetNumberOfLines(6); + } + + public override RenderItemType Type => RenderItemType.Reference; + + /// + /// Sets number of lines via the width or height percent + /// + internal void SetNumberOfLines(int numberOfLines) + { + var percentOf = 100d / (double)numberOfLines; + switch (type) + { + case LinePatternType.Vertical: + widthPercent = percentOf; + break; + case LinePatternType.Horizontal: + heightPercent = percentOf; + break; + } + } + + public override void Render(StringBuilder sb) + { + _items.Add(LineItem); + base.Render(sb); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinearGradient.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinearGradient.cs new file mode 100644 index 0000000000..9c50b66e8a --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/LinearGradient.cs @@ -0,0 +1,70 @@ +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Utils; +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using EPPlus.Export.ImageRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer.Constants; +using OfficeOpenXml.Drawing.Style.Coloring; +using OfficeOpenXml.Drawing.Style.Fill; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Utils; +using System.Drawing; +using System.Globalization; +using TypeConv = OfficeOpenXml.Utils.TypeConversion; + + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + internal class LinearGradient : RenderItem + { + internal DrawGradientFill GradientFillExtra; + internal double Degrees; + + string _id; + bool userSpaceOnUse = false; + + public LinearGradient(DrawingBase renderer, string id) : base(renderer) + { + _id = id; + } + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append($""); + SetStopColors(sb, GradientFillExtra, PathFillMode.Norm); + sb.Append(""); + } + + private string GetOpacity(ExcelDrawingColorManager c) + { + var opacityTransform = c.Transforms?.FirstOrDefault(x => x.Type == OfficeOpenXml.Drawing.Style.Coloring.eColorTransformType.Alpha); + if (opacityTransform == null) return ""; + + return $"stop-opacity=\"{opacityTransform.Value.ToString("0")}%\""; + } + + private void SetStopColors(StringBuilder defSb, DrawGradientFill gradientFill, PathFillMode fillMode) + { + int ix = 0; + + //Svg requires starting at 0 and moving towards 100% Excel sometimes starts at 100 + //Sort to get around that + var sortedGradientColors = gradientFill.Colors.OrderBy(x => x.Position); + + foreach (var c in sortedGradientColors) + { + var color = ColorUtils.GetAdjustedColor(fillMode, c.Color); + // TODO: check if ix should be increased...? + defSb.Append($""); + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/MaskGroup.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/MaskGroup.cs new file mode 100644 index 0000000000..288095c0ea --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/MaskGroup.cs @@ -0,0 +1,40 @@ +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + internal class MaskGroup : RenderItem + { + protected string _id = null; + + protected List _items = new List(); + + public MaskGroup(DrawingBase renderer, string id) : base(renderer) + { + _id = id; + } + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append($""); + + foreach (var item in _items) + { + item.Render(sb); + } + + sb.Append(""); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/PatternItem.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/PatternItem.cs new file mode 100644 index 0000000000..a9a9c26931 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/PatternItem.cs @@ -0,0 +1,40 @@ +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Globalization; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + internal class PatternItem : RenderItem + { + string _id = null; + + protected List _items = new List(); + + public PatternItem(DrawingBase baseRend, string id) : base(baseRend) + { + _id = id; + } + + protected double heightPercent = 100d; + protected double widthPercent = 100d; + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append($""); + + foreach (var item in _items) + { + item.Render(sb); + } + + sb.Append(""); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/SymbolGroup.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/SymbolGroup.cs new file mode 100644 index 0000000000..da2ffff6c4 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/SymbolGroup.cs @@ -0,0 +1,48 @@ +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils +{ + internal class SymbolGroup : RenderItem + { + protected const string _urlRef = "url(#{0})"; + + protected string _id = null; + + protected List _items = new List(); + + internal string Mask = null; + + public SymbolGroup(DrawingBase renderer, string id) : base(renderer) + { + _id = id; + } + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append($""); + + foreach (var item in _items) + { + item.Render(sb); + } + + sb.Append(""); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridDefGroup.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridDefGroup.cs new file mode 100644 index 0000000000..2321bc63fc --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridDefGroup.cs @@ -0,0 +1,96 @@ +using EPPlus.Fonts.OpenType.Utils; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils.UtillNodes +{ + internal class DynamicGridDefGroup : RenderItem + { + protected const string _urlRef = "\"url(#{0})\""; + + internal string Id { get; private set; } + + internal List Items = new List(); + + internal LinePattern LnPatternHorizontal { get; private set; } + internal LinePattern LnPatternVertical { get; private set; } + + FadeOutMask maskItem; + + LinearGradient fadeOutGradient; + + DynamicGridItem gridItem; + + internal string TopId { get; private set; } + + public DynamicGridDefGroup(DrawingBase renderer, string id, int linesX, int linesY): base(renderer) + { + Id = id; + + string lnGradId = id + "_lnGradFade"; + string maskId = id + "_maskFade"; + string horzId = id + "_lnHorizontal"; + string verId = id + "_lnVertical"; + + fadeOutGradient = CreateFadeOutGradient(lnGradId); + Items.Add(fadeOutGradient); + + maskItem = new FadeOutMask(renderer, maskId, string.Format("url(#{0})", lnGradId)); + + Items.Add(maskItem); + + LnPatternHorizontal = new LinePattern(renderer, horzId, LinePatternType.Horizontal); + LnPatternVertical = new LinePattern(renderer, verId, LinePatternType.Vertical); + + SetNumLines(linesX, linesY); + + Items.Add(LnPatternHorizontal); + Items.Add(LnPatternVertical); + + gridItem = new DynamicGridItem(renderer, id, maskId, horzId, verId); + Items.Add(gridItem); + } + + internal void SetNumLines(int numLinesHorizontal, int numLinesVertical) + { + LnPatternHorizontal.SetNumberOfLines(numLinesHorizontal); + LnPatternVertical.SetNumberOfLines(numLinesVertical); + } + + LinearGradient CreateFadeOutGradient(string id) + { + var colors = new List(); + colors.Add(Color.Black); + colors.Add(Color.White); + + var stops = new List(); + stops.Add(0); + stops.Add(100); + + fadeOutGradient = new LinearGradient(DrawingRenderer, id); + fadeOutGradient.GradientFillExtra = new DrawGradientFill(colors, stops); + + return fadeOutGradient; + } + + public override RenderItemType Type => RenderItemType.Group; + + public override void Render(StringBuilder sb) + { + sb.Append($""); + + foreach (var item in Items) + { + item.Render(sb); + } + + sb.Append(""); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridItem.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridItem.cs new file mode 100644 index 0000000000..bfd4837d0d --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/DynamicGridItem.cs @@ -0,0 +1,43 @@ +using EPPlus.Export.ImageRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Interfaces; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Drawing.Style.Fill; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils.UtillNodes +{ + internal class DynamicGridItem : SymbolGroup + { + SvgRenderRectItem HorizontalLines = null; + SvgRenderRectItem VerticalLines = null; + + public DynamicGridItem(DrawingBase renderer, string id, string maskId, string linesHorizontalId, string linesVerticalId) : base(renderer, id) + { + Mask = string.Format(_urlRef, maskId); + + HorizontalLines = IntitalizeRect(); + HorizontalLines.FillColor = string.Format(_urlRef, linesHorizontalId); + + VerticalLines = IntitalizeRect(); + VerticalLines.FillColor = string.Format(_urlRef, linesVerticalId); + + _items.Add(HorizontalLines); + _items.Add(VerticalLines); + } + + SvgRenderRectItem IntitalizeRect() + { + var rect = new SvgRenderRectItem(DrawingRenderer, Bounds); + rect.Width = 100; + rect.Height = 100; + rect.Suffix = "%"; + + return rect; + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/FadeOutMask.cs b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/FadeOutMask.cs new file mode 100644 index 0000000000..6ede276a63 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DefinitionUtils/UtillNodes/FadeOutMask.cs @@ -0,0 +1,26 @@ +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace EPPlus.Export.ImageRenderer.Svg.DefinitionUtils.UtillNodes +{ + internal class FadeOutMask : MaskGroup + { + public FadeOutMask(DrawingBase renderer, string id, string rectFillId) : base(renderer, id) + { + var rect = new SvgRenderRectItem(DrawingRenderer, Bounds); + rect.Width = 100; + rect.Height = 100; + rect.Suffix = "%"; + + rect.FillColor = rectFillId; + + _items.Add(rect); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/DrawingRenderer.cs b/src/EPPlus/Drawing/Renderer/DrawingRenderer.cs new file mode 100644 index 0000000000..9f1f5d2a33 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/DrawingRenderer.cs @@ -0,0 +1,62 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.Utils; +using EPPlus.Export.Utils; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Graphics; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport; +using OfficeOpenXml.Interfaces.Drawing.Text; +using System.Collections.Generic; + +namespace OfficeOpenXml.Drawing.Renderer +{ + internal abstract class DrawingRenderer + { + internal DrawingRenderer(ExcelDrawing drawing) + { + Drawing = drawing; + Bounds = drawing.GetBoundingBox(); + + var wb = drawing._drawings.Worksheet.Workbook; + Theme = wb.ThemeManager.GetOrCreateTheme(); + RenderContext = wb.RenderContext; + + var shaper = RenderContext.FontEngine.GetTextShaper(Theme.FontScheme.MajorFont[0].Typeface); + TextMeasurer = new OpenTypeFontTextMeasurer(shaper); + } + + + internal DrawingRenderer() + { + //Drawing = drawing; + //Bounds = drawing.GetBoundingBox(); + + //var wb = drawing._drawings.Worksheet.Workbook; + //Theme = wb.ThemeManager.GetOrCreateTheme(); + } + + internal readonly StyleCache _styleCache = new StyleCache(); + public ExcelDrawing Drawing { get; } + public ExcelTheme Theme { get;} + public ExcelWorkbook Workbook => Drawing._drawings.Worksheet.Workbook; + internal ITextMeasurer TextMeasurer { get; } + internal RenderContext RenderContext { get; } + public List RenderItems { get; } = new List(); + internal BoundingBox Bounds = new BoundingBox(); + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/IDrawingChartAxis.cs b/src/EPPlus/Drawing/Renderer/IDrawingChartAxis.cs new file mode 100644 index 0000000000..9ac62a9c9d --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/IDrawingChartAxis.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ + +using System.Collections.Generic; + +namespace EPPlusImageRenderer.Svg +{ + internal interface IDrawingChartAxis + { + List Values + { + get; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/DrawingRenderItemExtentions.cs b/src/EPPlus/Drawing/Renderer/RenderItems/DrawingRenderItemExtentions.cs new file mode 100644 index 0000000000..0ef5dde160 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/DrawingRenderItemExtentions.cs @@ -0,0 +1,249 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Drawing.Style.Coloring; +using OfficeOpenXml.Drawing.Style.Effect; +using OfficeOpenXml.Drawing.Theme; +using System; +using tc = OfficeOpenXml.Utils.TypeConversion; +using System.Drawing; +using OfficeOpenXml.Drawing.Renderer.RenderItems.Fill; +namespace EPPlusImageRenderer.RenderItems +{ + internal enum SvgFillType + { + SolidFill, + GradientFill, + PatternFill + } + internal static class DrawingRenderItemExtentions + { + internal static void SetDrawingPropertiesFill(this RenderItem item, ExcelTheme theme, ExcelDrawingFill fill, ExcelDrawingColorManager color, bool gradientUserSpace = false, ExcelDrawingThemeColorManager nullColor = null) + { + switch (fill.Style) + { + + case eFillStyle.PatternFill: + item.PatternFill = new DrawingRenderPatternFill(theme, fill.PatternFill, item.FillColorSource); + break; + case eFillStyle.BlipFill: + item.BlipFill = new DrawingRenderBlipFill(fill.BlipFill); + break; + default: + SetDrawingPropertiesFillBasic(item, theme, fill, color, gradientUserSpace, nullColor); + break; + } + } + internal static void SetDrawingPropertiesFillBasic(this RenderItem item, ExcelTheme theme, ExcelDrawingFillBasic fill, ExcelDrawingColorManager color, bool gradientUserSpaceOnUse, ExcelDrawingThemeColorManager nullColor) + { + double? opacity = null; + switch (fill.Style) + { + case eFillStyle.NoFill: + if (fill.IsEmpty) //Do NOT remove. This if is required for Shapes + { + item.FillColor = GetFillColor(theme, fill, color, item.FillColorSource, out opacity, null); + } + else + { + item.FillColor = "none"; + } + break; + case eFillStyle.SolidFill: + item.FillColor = GetFillColor(theme, fill, color, item.FillColorSource, out opacity); + break; + case eFillStyle.GradientFill: + item.GradientFill = new DrawingRenderGradientFill(theme, fill.GradientFill, gradientUserSpaceOnUse); + item.FillColor = null; + break; + } + if (opacity.HasValue) + { + item.FillOpacity = opacity; + } + } + internal static void SetDrawingPropertiesBorder(this RenderItem item, ExcelTheme theme, ExcelDrawingBorder border, ExcelChartStyleColorManager color, bool hasBorder, double defaultWidth = 1.5, bool grandientUserSpaceOnUse=true) + { + double? opacity = null; + if (border == null) + { + if (hasBorder) + { + item.BorderColor = GetFillColor(theme, null, color, item.BorderColorSource, out opacity, theme.ColorScheme.Dark1); + } + } + else + { + switch (border.Fill.Style) + { + case eFillStyle.NoFill: + if (border.Fill.IsEmpty) + { + item.BorderColor = GetFillColor(theme, border.Fill, color, item.BorderColorSource, out opacity); + } + else + { + item.BorderColor = "none"; + } + break; + case eFillStyle.SolidFill: + item.BorderColor = GetFillColor(theme, border.Fill, color, item.BorderColorSource, out opacity); + item.BorderGradientFill = null; + break; + case eFillStyle.GradientFill: + item.BorderGradientFill = new DrawingRenderGradientFill(theme, border.Fill.GradientFill, grandientUserSpaceOnUse); + item.BorderColor = null; + break; + } + } + + if (opacity.HasValue) + { + item.BorderOpacity = opacity; + } + + if (hasBorder && item.BorderColorSource != PathFillMode.None) + { + item.BorderWidth = (border?.Width??0D) == 0D ? defaultWidth : border.Width; + if (border!=null && border.LineStyle.HasValue && border.LineStyle != eLineStyle.Solid) + { + item.BorderDashArray = GetDashArray(border, item.BorderWidth.Value); + } + if (border != null && border.CompoundLineStyle != eCompoundLineStyle.Single) + { + item.CompoundLineStyle = (CompoundLineStyle)border.CompoundLineStyle; + //TODO:Add support double compound borders. + } + } + } + internal static void SetDrawingPropertiesEffects(this RenderItem item, ExcelTheme theme, ExcelDrawingEffectStyle effect) + { + if (effect.HasGlow) + { + item.GlowRadius = effect.Glow.Radius; + var gc = tc.ColorConverter.GetThemeColor(theme, effect.Glow.Color); + item.GlowColor = "#" + gc.ToArgb().ToString("x8").Substring(2); + } + if (effect.HasOuterShadow) + { + item.OuterShadowEffect = new RenderShadowEffect(); + item.OuterShadowEffect.OuterShadowEffectColor = tc.ColorConverter.GetThemeColor(theme, effect.OuterShadow.Color); + item.OuterShadowEffect.Direction = effect.OuterShadow.Direction; + item.OuterShadowEffect.BlurRadius = effect.OuterShadow.BlurRadius; + item.OuterShadowEffect.Distance = effect.OuterShadow.Distance; + } + } + + private static double[] GetDashArray(ExcelDrawingBorder border, double width) + { + var lw = (int)Math.Round(width * ExcelDrawing.EMU_PER_POINT / ExcelDrawing.EMU_PER_PIXEL); + switch (border.LineStyle) + { + case eLineStyle.Dot: + return new double[] { lw, 4 * lw }; + case eLineStyle.DashDot: + return new double[] { 4 * lw, 3 * lw, lw, 3 * lw }; + case eLineStyle.Dash: + return new double[] { 4 * lw, 3 * lw }; + case eLineStyle.LongDash: + return new double[] { 8 * lw, 3 * lw }; + case eLineStyle.LongDashDot: + return new double[] { 8 * lw, 3 * lw, lw, 3 * lw }; + case eLineStyle.LongDashDotDot: + return new double[] { 8 * lw, 3 * lw, lw, 3 * lw, lw, 3 * lw }; + case eLineStyle.SystemDash: + return new double[] { 3 * lw, lw }; + case eLineStyle.SystemDot: + return new double[] { lw, lw }; + case eLineStyle.SystemDashDot: + return new double[] { 3 * lw, lw, lw, lw }; + case eLineStyle.SystemDashDotDot: + return new double[] { 3 * lw, lw, lw, lw, lw, lw }; + } + return null; + } + + private static string GetFillColor(ExcelTheme theme, ExcelDrawingFillBasic fill, ExcelDrawingColorManager styleFillColor, PathFillMode fillColorSource, out double? opacity, ExcelDrawingThemeColorManager nullColor = null) + { + opacity = null; + if (fillColorSource == PathFillMode.None) + { + return "none"; + } + + Color fc; + fc = tc.ColorConverter.GetThemeColor(nullColor ?? theme.ColorScheme.Accent1); + if (fill == null || fill.Style == eFillStyle.NoFill) + { + //if(nullColor != null) + //{ + // fc = tc + //} + //if (styleFillColor == null) + //{ + // //There is no Style-Specified color. Themed Fill should be applied if it exists + // //Fallback to theme + // if (theme.FormatScheme.BackgroundFillStyle != null) + // { + // //Usually, at least for chart objects if the theme fill is not NoFill it is Subtle + // var subtleBg = theme.FormatScheme.BackgroundFillStyle[0]; + // if (subtleBg.IsEmpty == false) + // { + // if (subtleBg.Style == eFillStyle.SolidFill) + // { + // if (subtleBg.SolidFill.Color.ColorType == eDrawingColorType.Scheme) + // { + // //The theme color is PhClr which is fallback color to style. + // //Style does not exist. But The base theme schemecolor does. + // //Hardcoded defaults to solid fill according to docs is Bg1 + // //Specifically SolidFill has a fallback to bg1 + + // var bg1 = theme.ColorScheme.GetColorByEnum(eSchemeColor.Background1); + // fc = tc.ColorConverter.GetThemeColor(bg1); + // } + // } + // else + // { + // //alternatively accent 1 + // fc = subtleBg.Color; + // } + // //var style = subtleBg.Style; + // //subtleBg.LoadFill(); + // //subtleBg.Color; + // } + // } + //} + } + else if (fill.Style == eFillStyle.SolidFill) + { + //Send in styleFill as well since a solid fill can refer to style color + fc = tc.ColorConverter.GetThemeColor(theme, fill.SolidFill.Color, styleFillColor); + } + else + { + return string.Empty; + } + + fc = tc.ColorConverter.GetAdjustedColor(fillColorSource, fc); + if (fc.A < 255 && fc != Color.Empty) + { + opacity = fc.A / 255D; + } + return "#" + fc.ToArgb().ToString("x8").Substring(2); + } + } + +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderBlipFill.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderBlipFill.cs new file mode 100644 index 0000000000..4f75779418 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderBlipFill.cs @@ -0,0 +1,29 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.Utils; +using EPPlus.Graphics; +using OfficeOpenXml.Drawing.Style.Fill; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OfficeOpenXml.Drawing.Renderer.RenderItems.Fill +{ + public class DrawingRenderBlipFill : RenderBlipFill + { + //private ExcelDrawingBlipFill _blipFill; + + internal DrawingRenderBlipFill(ExcelDrawingBlipFill blipFill) + { + //_blipFill = blipFill; + ImageBytes = blipFill.Image.ImageBytes; + ImageBounds = new BoundingBox(blipFill.Image.Bounds.Width, blipFill.Image.Bounds.Height); + ContentType = blipFill.ContentType; + Stretch = blipFill.Stretch; + StretchOffset = blipFill.StretchOffset.AsOffsetRectangle(); + Tile = blipFill.Tile.AsFillTile(); + + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderGradientFill.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderGradientFill.cs new file mode 100644 index 0000000000..b044225512 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderGradientFill.cs @@ -0,0 +1,57 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.ImageRenderer.RenderItems; +using OfficeOpenXml.Drawing.Style.Fill; +using OfficeOpenXml.Drawing.Theme; +using System.Collections.Generic; +using System.Drawing; +using EPPlusColorConverter = OfficeOpenXml.Utils.TypeConversion.ColorConverter; +using System; +using EPPlus.Export.Utils; + +namespace EPPlus.DrawingRenderer.RenderItems +{ + internal class DrawingRenderGradientFill : RenderGradientFill + { + public DrawingRenderGradientFill(ExcelTheme theme, ExcelDrawingGradientFill gradientFill, bool userSpaceOnUse) : base() + { + //this.Settings = gradientFill; + for (int i = 0; i < gradientFill.Colors.Count; i++) + { + var opacity = EPPlusColorConverter.GetOpacity(gradientFill.Colors[i].Color); + var c = new GradientFillColor(gradientFill.Colors[i].Position, EPPlusColorConverter.GetThemeColor(theme, gradientFill.Colors[i].Color)); + c.Opacity = opacity; + Colors.Add(c); + } + + if (gradientFill.FocusPoint != null) + { + FocusPoint = gradientFill.FocusPoint.AsOffsetRectangle(); + } + + if (gradientFill.TileRectangle != null) + { + TileRectangle = gradientFill.TileRectangle.AsOffsetRectangle(); + } + + ShadePath = (ShadePath)gradientFill.ShadePath; + + if (gradientFill.LinearSettings != null) + { + LinearSettings.Angle = gradientFill.LinearSettings.Angle; + LinearSettings.Scaled = gradientFill.LinearSettings.Scaled; + } + UserSpaceOnUse = userSpaceOnUse; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderPatternFill.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderPatternFill.cs new file mode 100644 index 0000000000..9741082b9a --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Fill/DrawingRenderPatternFill.cs @@ -0,0 +1,26 @@ +using EPPlus.DrawingRenderer.RenderItems; +using OfficeOpenXml.Drawing.Style.Fill; +using OfficeOpenXml.Drawing.Theme; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using tc = OfficeOpenXml.Utils.TypeConversion; + +namespace OfficeOpenXml.Drawing.Renderer.RenderItems.Fill +{ + internal class DrawingRenderPatternFill : RenderPatternFill + { + private ExcelDrawingPatternFill _patternFill; + + public DrawingRenderPatternFill(ExcelTheme theme, ExcelDrawingPatternFill patternFill, EPPlus.DrawingRenderer.PathFillMode fillColorSource) + { + _patternFill = patternFill; + base.PatternType = (FillPatternStyle)patternFill.PatternType; + ForegroundColor = tc.ColorConverter.GetThemeColor(theme, _patternFill.ForegroundColor); + BackgroundColor = tc.ColorConverter.GetThemeColor(theme, _patternFill.BackgroundColor); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingParagraphRenderItem.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingParagraphRenderItem.cs new file mode 100644 index 0000000000..804abe2ef5 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingParagraphRenderItem.cs @@ -0,0 +1,269 @@ +using EPPlus.DrawingRenderer; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.Integration.RichText; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Collections.Generic; +using OfficeOpenXml.Interfaces.Fonts; + +namespace OfficeOpenXml.Drawing.Renderer.TextBox +{ + internal class DrawingParagraphRenderItem : ParagraphRenderItem + { + /// + /// Create basic empty paragraph + /// + /// + /// + public DrawingParagraphRenderItem(RenderContext renderContext, DrawingTextBody textBody, BoundingBox parent) + : base(renderContext, parent, textBody) + { + ParagraphLineSpacing = GetParagraphLineSpacingInPoints(100, (TextShaper)RenderContext.FontEngine.GetShaperForFont(DefaultParagraphFont), DefaultParagraphFont.Size); + } + + /// + /// Create paragraph and import a singular text/richText + /// + /// + /// + /// + public DrawingParagraphRenderItem(RenderContext renderContext, DrawingTextBody textBody, BoundingBox parent, string text) + : this(renderContext, textBody, parent) + { + ImportLinesAndTextRunsDefault(text); + } + + /// + /// Create paragraph and import all textruns from ExcelDrawingParagraph + /// + /// + /// + /// + /// + public DrawingParagraphRenderItem(RenderContext renderContext, DrawingTextBody textBody, BoundingBox parent, ExcelDrawingParagraph p, string textIfEmpty = null) + : base(renderContext, parent, textBody, false) + { + IsFirstParagraph = p == p._paragraphs[0]; + ImportStyleInfo(textBody, p); + HorizontalAlignment = (TextAlignment)(int)p.HorizontalAlignment; + ImportMarginAndIndent(p); + + DefaultParagraphFont = new FontFormatBase(p.DefaultRunProperties.GetMeasureFont()); + + ImportLineSpacing(p.LineSpacing.LineSpacingType, p.LineSpacing.Value); + + ImportLinesAndTextRuns(p, textIfEmpty); + } + + private double GetParagraphLineSpacingInPoints(double spacingValue, TextShaper fmExact, float fontSize) + { + if (_lsType == TextLineSpacing.Exactly) + { + if (IsFirstParagraph) + { + LineSpacingAscendantOnly = spacingValue; + } + return spacingValue; + } + else + { + var multiplier = (spacingValue / 100); + _lsMultiplier = multiplier; + if (IsFirstParagraph) + { + LineSpacingAscendantOnly = multiplier * fmExact.GetAscentInPoints(fontSize); + } + return multiplier * fmExact.GetLineHeightInPoints(fontSize); + } + } + + private void ImportLinesAndTextRuns(ExcelDrawingParagraph p, string textIfEmpty) + { + if (p.TextRuns.Count == 0 && string.IsNullOrEmpty(textIfEmpty) == false) + { + ImportLinesAndTextRunsDefault(textIfEmpty, p.DefaultRunProperties); + } + else + { + //Log line positions and run sizes + GenerateRichText(p.TextRuns); + TextIfEmptyIsNull = string.IsNullOrEmpty(textIfEmpty); + //Initalize and wrap textruns + WrapTextFragmentsAndGenerateTextRuns(); + ImportStyles(p.TextRuns, p.DefaultRunProperties); + } + } + + internal void ImportLinesAndTextRunsDefault(string textIfEmpty, ExcelTextFont font = null) + { + ImportLinesAndTextRunsBase(textIfEmpty); + //Import RichText data to each run + foreach (var run in Runs) + { + var textRun = (DrawingTextRunRenderItem)run; + ImportStyleFallback(font, textRun); + } + } + + /// + /// Log linebreak positions and sizes of the runs + /// So that we can easily know what textfragment is on what line and what size it has later + /// + /// + void GenerateRichText(ExcelDrawingTextRunCollection runs/*, List? optionLst = null*/) + { + //var lstOfRichText = runs.ExportToOpenTypeFormat(); + var lstOfRichText = runs.ExportToImageRendererFormat(); + foreach (var rt in lstOfRichText) + { + _textFragments.Add(rt); + } + } + + private void ImportStyleInfo(DrawingTextBody textBody, ExcelDrawingParagraph p) + { + //If this paragraph has defaults of its own enter here + if (p.DefaultRunProperties.Fill != null && p.DefaultRunProperties.Fill.IsEmpty == false) + { + if (IsFirstParagraph) + { + if (p.DefaultRunProperties.Fill != null) + { + this.SetDrawingPropertiesFill(textBody.Theme, p.DefaultRunProperties.Fill, null); + } + } + else + { + //Drawingproperties has fallback to firstDefault but excel does not display it so we should not either. + if (p.DefaultRunProperties != p._paragraphs.FirstDefaultRunProperties) + { + this.SetDrawingPropertiesFill(textBody.Theme, p.DefaultRunProperties.Fill, null); + } + else + { + var fc = ColorConverter.GetThemeColor(textBody.Theme.ColorScheme.Light1); + fc = ColorConverter.GetAdjustedColor(PathFillMode.Norm, fc); + FillColor = "#" + fc.ToArgb().ToString("x8").Substring(2); + //Use shape fill somehow + //Maybe use a name property for fallback theme accent1 color? + } + } + } + else + { + if(p._paragraphs.Count != 0) + { + //Fallback to the defaults of the first paragraph + if (p._paragraphs[0].DefaultRunProperties != null && p._paragraphs[0].DefaultRunProperties.Fill != null && p._paragraphs[0].DefaultRunProperties.Fill.IsEmpty == false) + { + var fill = p._paragraphs[0].DefaultRunProperties.Fill; + this.SetDrawingPropertiesFill(textBody.Theme, fill, null); + } + else + { + var fc = ColorConverter.GetThemeColor(textBody.Theme.ColorScheme.Light1); + fc = ColorConverter.GetAdjustedColor(PathFillMode.Norm, fc); + FillColor = "#" + fc.ToArgb().ToString("x8").Substring(2); + //Use shape fill somehow + //Maybe use a name property for fallback theme accent1 color? + } + } + } + } + + private void ImportMarginAndIndent(ExcelDrawingParagraph p) + { + var indent = 48 * p.IndentLevel; + LeftMargin = p.LeftMargin + p.Indent + indent; + RightMargin = p.RightMargin; + + LeftMargin = LeftMargin.PixelToPoint(); + RightMargin = RightMargin.PixelToPoint(); + + _alignment = (TextAlignment)p.HorizontalAlignment; + LeftMargin = LeftMargin.PixelToPoint(); + RightMargin = RightMargin.PixelToPoint(); + } + + private void ImportAlignment(bool isAutoSize, double maxWidth, double parentWidth) + { + //if (isAutoSize == false) + //{ + //Bounds.Left = 0; + //Bounds.Width = ParentMaxWidth; + + ////Left is equal to left Paragraph margin + ////Textbody or Textbox are assumed to handle shape/chart margins + ////Paragraph handles only indentations/margins that is applied ON TOP of those margins + ////Paragraph left is the exact position where the text itself starts on the left + //Bounds.Left = GetAlignmentHorizontal(TextAlignment.Left); + //if (HorizontalAlignment == TextAlignment.Center) + //{ + // //Center is a bit strange the bounds really are the same as left or right aligned + // //It doesn't truly matter as only left min and right max play a role + // _centerAdjustment = GetAlignmentHorizontal(HorizontalAlignment); + //} + //Bounds.Width = parentWidth - RightMargin - LeftMargin; + //} + } + + private void ImportLineSpacing(eDrawingTextLineSpacing lsType, double lineSpacingValue) + { + _lsType = (TextLineSpacing)lsType; + var shaper = (TextShaper)RenderContext.FontEngine.GetShaperForFont(DefaultParagraphFont); + + ParagraphLineSpacing = GetParagraphLineSpacingInPoints( + lineSpacingValue, + shaper, + DefaultParagraphFont.Size); + } + + void ImportStyleFallback(ExcelTextFont font, DrawingTextRunRenderItem run) + { + if (font != null) + { + //IF there is a default ExcelTextFont use it + run.ImportExcelTextFont(font, DefaultParagraphFont); + } + else + { + //If not use the default for the whole paragraph (potentially user specified) + run.ImportFontData(DefaultParagraphFont); + } + } + + void ImportStyles(ExcelDrawingTextRunCollection textRuns, ExcelTextFont font) + { + //Import RichText data to each run + foreach (var run in Runs) + { + var textRun = (DrawingTextRunRenderItem)run; + + if (textRuns.Count != 0 && run.OriginalRtIdx != -1) + { + //Import existing textrun + textRun.ImportTextRunBase(textRuns[run.OriginalRtIdx], _layoutSystem.InputFragments[run.OriginalRtIdx].RichTextOptions); + } + else + { + //Import default properties or fallback font + ImportStyleFallback(font, textRun); + } + } + } + protected override TextRunRenderItem CreateTextRun(BoundingBox parent, string displayText, int origRtIdx) + { + return new DrawingTextRunRenderItem(Bounds, displayText, origRtIdx); + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs new file mode 100644 index 0000000000..3cbc496c86 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs @@ -0,0 +1,235 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.RenderItems.SvgItem; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using EPPlusImageRenderer.Svg; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Drawing.Renderer.TextBox +{ + public class DrawingTextBody : RenderTextBody + { + internal ExcelDrawing _drawing; + + internal ExcelTheme Theme { get; } + + public DrawingTextBody(RenderContext renderContext, ExcelDrawing drawing, BoundingBox parent, bool autoSize, bool clampedToParent = false) : base(renderContext, parent, autoSize) + { + _drawing = drawing; + Theme = drawing._drawings.Worksheet.Workbook.ThemeManager.GetOrCreateTheme(); + MaxWidth = parent.Width; + MaxHeight = parent.Height; + } + public DrawingTextBody(RenderContext renderContext, ExcelDrawing drawing, BoundingBox parent, double left, double top, double maxWidth, double maxHeight, bool clampedToParent = false, bool autoSize=false) : base(renderContext, parent, autoSize) + { + _drawing = drawing; + Theme = drawing._drawings.Worksheet.Workbook.ThemeManager.GetOrCreateTheme(); + Bounds.Left = left; + Bounds.Top = top; + Bounds.Width = maxWidth; + Bounds.Height = maxHeight; + MaxWidth = maxWidth; + MaxHeight = maxHeight; + } + + public void ImportParagraph(ExcelDrawingParagraph item, double startingY, string text = null) + { + bool isFirst = Paragraphs.Count == 0; + Text = text; + + var paragraph = CreateParagraph(this, item, Bounds, text); + paragraph.Bounds.Name = $"Container{Paragraphs.Count}"; + paragraph.Bounds.Top = startingY; + + if (AutoSize) + { + if (Paragraphs.Count == 0) + { + Bounds.Height = paragraph.Bounds.Height; + } + else + { + Bounds.Height += paragraph.Bounds.Height; + } + + if (Bounds.Width < paragraph.Bounds.Width || (Bounds.Width == MaxWidth && Paragraphs.Count == 0)) + { + Bounds.Width = paragraph.Bounds.Width; + } + } + Paragraphs.Add(paragraph); + RecalculateParagraphs(); + } + + //Horizontal alignment should technically be set directly in paragraph + //But as the text is not measured until a paragraph has been imported an autosized textbody + //does not know its maximum size until all its paragraphs has been imported + //thus after all have we need to adjust. + //The alternative would be to perform the performance heavy measurement twice. + internal void SetHorizontalAlignmentPosition() + { + foreach (var p in Paragraphs) + { + switch (p.HorizontalAlignment) + { + case TextAlignment.Left: + p.Bounds.Left = 0; + break; + case TextAlignment.Center: + p.Bounds.Left = (Bounds.Width / 2) - (p.Bounds.Width / 2); + break; + case TextAlignment.Right: + p.Bounds.Left = Bounds.Right - p.Bounds.Width; + break; + case TextAlignment.Distributed: + case TextAlignment.Justified: + case TextAlignment.JustifiedLow: + case TextAlignment.ThaiDistributed: + p.Bounds.Left = 0; //TODO: Set left for now as we do not support distributed spacing yet + break; + } + } + } + + internal TextAlignment TranslateHorizontalPosition(ExcelHorizontalAlignment alignment) + { + switch (alignment) + { + case ExcelHorizontalAlignment.Left: + return TextAlignment.Left; + case ExcelHorizontalAlignment.Center: + return TextAlignment.Center; + case ExcelHorizontalAlignment.Right: + return TextAlignment.Right; + case ExcelHorizontalAlignment.Distributed: + case ExcelHorizontalAlignment.CenterContinuous: + case ExcelHorizontalAlignment.Justify: + case ExcelHorizontalAlignment.General: + default: + return TextAlignment.Left; //TODO: Set left for now as we do not support distributed spacing yet + } + } + + internal virtual void ImportTextBodyAndParagraphs(ExcelTextBody body, ExcelHorizontalAlignment horizontalDefault = ExcelHorizontalAlignment.Left) + { + Text = null; + VerticalAlignment = (TextAnchoringType)body.Anchor; + + //We already apply bounds top via the parent Transform + double currentHeight = 0; + double largestWidth = double.MinValue; + + //var defaultAlignment = TranslateHorizontalPosition(horizontalDefault); + + body.GetInsetsInPoints(out double left, out double top, out double right, out double bottom); + + if (AutoSize == false) + { + LeftMargin = left; + TopMargin = top; + RightMargin = right; + BottomMargin = bottom; + + MaxHeight = MaxHeight - top - bottom; + MaxWidth = MaxWidth - left - right; + Height = MaxHeight; + Width = MaxWidth; + } + + foreach (var paragraph in body.Paragraphs) + { + ImportParagraph(paragraph, currentHeight); + var addedPara = Paragraphs.Last(); + //addedPara.HorizontalAlignment = defaultAlignment; + + currentHeight = addedPara.Bounds.Bottom; + largestWidth = Math.Max(largestWidth, addedPara.Bounds.Width); + } + + + if (Paragraphs != null && Paragraphs.Count() > 0 && AutoSize) + { + Bounds.Height = currentHeight; + } + + //Ensure contentBounds are calculated and paragraphs don't overlap + RecalculateParagraphs(); + + //Alignment adjustment for e.g. ChartTitles one paragraph may be longer than another + //Therefore as paragraphs have no awareness of eachother we must compare and adjust + foreach (var paragraph in body.Paragraphs) + { + SetHorizontalAlignmentPosition(); + } + + Bounds.Top = GetAlignmentVertical(); + } + + //internal override void AppendRenderItems(List renderItems) + //{ + // SvgGroupItem groupItem; + // if (Bounds.Parent.Rotation == 0) //If the parent is rotated, we should not apply rotation again. This is usually when the parent is a textbox. + // { + // groupItem = new SvgGroupItem(DrawingRenderer, Bounds, Bounds.Rotation); + // } + // else + // { + // groupItem = new SvgGroupItem(DrawingRenderer, Bounds); + // } + + // if (FontColorString != null) + // { + // groupItem.GroupTransform += $" fill=\"{FontColorString}\""; + // } + + // renderItems.Add(groupItem); + // foreach (SvgParagraphItem item in Paragraphs) + // { + // renderItems.Add(item); + // } + // renderItems.Add(new SvgEndGroupItem(DrawingRenderer, Bounds)); + //} + + internal DrawingParagraphRenderItem CreateParagraph(DrawingTextBody textBody, BoundingBox parent) + { + return new DrawingParagraphRenderItem(RenderContext, textBody, parent); + } + + internal DrawingParagraphRenderItem CreateParagraph(DrawingTextBody textBody, ExcelDrawingParagraph paragraph, BoundingBox parent, string textIfEmpty = null) + { + return new DrawingParagraphRenderItem(RenderContext, textBody, parent, paragraph, textIfEmpty); + } + + /// + /// + /// + /// + /// + /// + protected override ParagraphRenderItem CreateParagraph(BoundingBox parent, string textIfEmpty = "") + { + return new DrawingParagraphRenderItem(RenderContext, this, parent, textIfEmpty); + } + + protected override ParagraphRenderItem CreateParagraph(BoundingBox parent, IRichTextFormatSimple richText) + { + var paragraph = new SvgParagraphRenderItem(RenderContext, this, parent, "", false); + paragraph.AddRichText(richText); + return paragraph; + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBox.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBox.cs new file mode 100644 index 0000000000..13a6eac205 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBox.cs @@ -0,0 +1,85 @@ +using EPPlus.Graphics; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; +namespace OfficeOpenXml.Drawing.Renderer.TextBox +{ + public class DrawingTextBox : RenderTextbox + { + ExcelDrawing _drawing; + internal DrawingTextBox(ExcelDrawing drawing, BoundingBox parent, double left, double top, double width, double height, double maxWidth = double.NaN, double maxHeight = double.NaN) : base(parent, left, top, width, height, maxWidth, maxHeight) + { + Init(drawing, parent, maxWidth, maxHeight); + Left = left; + Top = top; + } + + private void Init(ExcelDrawing drawing, BoundingBox parent, double maxWidth, double maxHeight) + { + Parent = parent; + _drawing= drawing; + var renderContext = drawing._drawings.Worksheet.Workbook.RenderContext; + TextBody = new DrawingTextBody(renderContext, drawing, _marginGroup.Bounds, true); + TextBody.MaxWidth = maxWidth; + TextBody.MaxHeight = maxHeight; + } + + internal DrawingTextBox(ExcelDrawing drawing, BoundingBox parent, double maxWidth, double maxHeight) : base(parent, maxWidth, maxHeight) + { + Init(drawing, parent, maxWidth, maxHeight); + } + + internal void AddText(string text = null) + { + TextBody.AddParagraph(text); + } + + DrawingTextBody _textBody; + + public DrawingTextBody GetTextBody() + { + return (DrawingTextBody)TextBody; + } + + public void SetDrawingTextBody(DrawingTextBody tb) + { + TextBody = tb; + } + + public override RenderTextBody TextBody { get { return _textBody; } set { _textBody = (DrawingTextBody)value; } } + + internal void ImportTextBodyAndParagraphs(ExcelTextBody body, bool useDefaults = true, ExcelHorizontalAlignment horizontalDefault = ExcelHorizontalAlignment.Left) + { + double l, r, t, b; + if (useDefaults) + { + body.GetInsetsOrDefaults(out l, out t, out r, out b); + } + else + { + body.GetInsetsInPoints(out l, out t, out r, out b); + } + LeftMargin = l; + TopMargin = t; + RightMargin = r; + BottomMargin = b; + + _textBody.ImportTextBodyAndParagraphs(body, horizontalDefault); + } + + internal void ImportParagraph(ExcelDrawingParagraph item, double startingY, string text = null) + { + _textBody.ImportParagraph(item, startingY, text); + } + + //internal void AddText(double startingY, string text = null) + //{ + // TextBody.AddParagraph(startingY, text); + //} + } +} diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextRunItem.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextRunItem.cs new file mode 100644 index 0000000000..7acef0d815 --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextRunItem.cs @@ -0,0 +1,182 @@ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Export.ImageRenderer.RenderItems.Shared; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using System; +using System.Collections.Generic; +using System.Drawing; + + +namespace OfficeOpenXml.Drawing.Renderer.TextBox +{ + internal class DrawingTextRunRenderItem : TextRunRenderItem + { + /// + /// Most basic of all textruns without even a font + /// + /// + /// + /// /// + internal DrawingTextRunRenderItem(BoundingBox parent, string text, int origRtIndex) : base(parent, text, origRtIndex) + { + + } + + /// + /// TextRunBase holds style info + /// baseFont is most likely a OpenTypeFontInfoBase made out of the font but we don't want to 'new' it every time we import + /// + /// + /// + internal void ImportTextRunBase(ExcelParagraphTextRunBase run, IFontFormatBase baseFont) + { + InitializeBase(new FontFormatBase(run.GetMeasurementFont())); + _currentText = string.IsNullOrEmpty(_currentText) ? run.Text : _currentText; + _isFirstInParagraph = run.IsFirstInParagraph; + _baseline = run.Baseline; + ImportExcelStyleInfo(run.Fill, run.FontItalic, run.FontBold, run.FontUnderLine, run.UnderLineColor, run.FontStrike); + SetClippingHeightToCurrentTextBoxBottom((BoundingBox)Bounds.Parent); + } + + /// + /// Text font holds style info. + /// baseFont is most likely a OpenTypeFontInfoBase made out of the font but we don't want to 'new' it every time we import + /// + /// + /// + internal void ImportExcelTextFont(ExcelTextFont font, IFontFormatBase baseFont) + { + InitializeBase(baseFont); + _baseline = font.Baseline; + + //Adjusts visual font size for sub and superscript + if (_baseline != 0) + { + _measurementFont.Size *= (float)(1 - (Math.Abs(_baseline) / 100)); + } + //Must be done after font adjustment + //Parent and clipping height must be calculated dependent on content + ImportExcelStyleInfo(font.Fill, font.Italic, font.Bold, font.UnderLine, font.UnderLineColor, font.Strike); + //Assumes texbox uses auto-size? + AdjustParentAndSetClippingHeight((BoundingBox)Bounds.Parent); + } + + /// + /// Import textrun with only font data + /// + /// + /// + /// + /// + internal DrawingTextRunRenderItem(BoundingBox parent, IFontFormatBase font, string displayText, bool adjustParent = true) : base(parent, font, displayText) + { + //Parent and clipping height must be calculated dependent on content + if (adjustParent) + { + AdjustParentAndSetClippingHeight(parent); + } + else + { + //If auto-size is not on? + SetClippingHeightToCurrentTextBoxBottom(parent); + } + //Since only font there is no direct style info to import + } + + /// + /// Import TextRun from Default paragraph properties/ExcelTextFont + /// + /// + /// + /// Legacy format + /// + internal DrawingTextRunRenderItem(BoundingBox parent, string text, ExcelTextFont font, string displayText) : base(parent, text, new FontFormatBase(font.GetMeasureFont()), displayText) + { + _baseline = font.Baseline; + + //Adjusts visual font size for sub and superscript + if (_baseline != 0) + { + _measurementFont.Size *= (float)(1 - (Math.Abs(_baseline) / 100)); + } + //Must be done after font adjustment + //Parent and clipping height must be calculated dependent on content + ImportExcelStyleInfo(font.Fill, font.Italic, font.Bold, font.UnderLine, font.UnderLineColor, font.Strike); + AdjustParentAndSetClippingHeight(parent); + } + + /// + /// Import text run from ParagraphTextRun + /// + /// new format + /// + /// + internal DrawingTextRunRenderItem(BoundingBox parent, ExcelParagraphTextRunBase run, string displayText = "") : base(parent, run.Text, new FontFormatBase(run.GetMeasurementFont()), displayText) + { + //This is pre-determined/irrelevant here and does not need to be calculated as sizes are already what they should + _isFirstInParagraph = false; + //Has getXmlNodePercentage, therefore no need for conversion + _baseline = run.Baseline; + + ImportExcelStyleInfo(run.Fill, run.FontItalic, run.FontBold, run.FontUnderLine, run.UnderLineColor, run.FontStrike); + + //This one cannot change parent size as it is pre-determined. No autosize etc. therefore no AdjustParentAndSetClippingHeight and different clipping height. + + SetClippingHeightToCurrentTextBoxBottom(parent); + } + + private void ImportExcelStyleInfo(ExcelDrawingFill fill, bool italic, bool bold, eUnderLineType uType, Color uColor, eStrikeType strikeType) + { + ImportDrawingFill(fill); + ImportRichTextInfo(italic, bold, uType, uColor, strikeType); + } + + private void AdjustParentAndSetClippingHeight(BoundingBox parent) + { + if (parent.Height < _measurementFont.Size) + { + parent.Height = _measurementFont.Size; + } + + CalculateClippingHeightFromTextBodyParent(); + } + + void ImportDrawingFill(ExcelDrawingFill fill) + { + if (fill.IsEmpty == false && fill.Style == eFillStyle.SolidFill) + { + FillColor = "#" + fill.Color.To6CharHexString(); + } + + //Backup? Should probably be removed or fallback + if (fill.Style == eFillStyle.SolidFill) + { + FillColor = "#" + fill.Color.To6CharHexString(); + } + } + + void ImportRichTextInfo(bool italic, bool bold, eUnderLineType uType, Color uColor, eStrikeType strikeType) + { + _isItalic = italic; + _isBold = bold; + _underLineType = (eDrawingUnderLineType)uType; + _underlineColor = uColor; + _strikeType = (eDrawingStrikeType)strikeType; + } + + void SetClippingHeightToCurrentTextBoxBottom(BoundingBox parent) + { + //To get clipping height we need to get the textbody bounds + if (parent != null && parent.Parent != null && parent.Parent.Parent != null) + { + ClippingHeight = ((BoundingBox)parent.Parent.Parent).Bottom; + } + } + } +} diff --git a/src/EPPlus/Drawing/Renderer/Shape/ShapeDefinition.cs b/src/EPPlus/Drawing/Renderer/Shape/ShapeDefinition.cs new file mode 100644 index 0000000000..8ad13f359d --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/Shape/ShapeDefinition.cs @@ -0,0 +1,40 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using EPPlus.DrawingRenderer.ShapeDefinitions; +using EPPlus.DrawingRenderer; + +namespace OfficeOpenXml.Drawing.Renderer.Shape +{ + //[DebuggerDisplay("{Style}")] + //internal class ShapeDefinition : EPPlus.DrawingRenderer.ShapeDefinitions.ShapeDefinitionBase + //{ + // public ShapeDefinition() : base() + // { + + // } + // /// + // /// Clone constructor + // /// + // /// The original to clone from + // public ShapeDefinition(ShapeDefinition original) : base(original) + // { + // } + //} +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs new file mode 100644 index 0000000000..e00d01666c --- /dev/null +++ b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs @@ -0,0 +1,531 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer; +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.DrawingRenderer.ShapeDefinitions; +using EPPlus.DrawingRenderer.Svg; +using EPPlus.Export.ImageRenderer.Utils; +using EPPlus.Export.Utils; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using EPPlusImageRenderer; +using EPPlusImageRenderer.RenderItems; +using OfficeOpenXml; +using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.Utils.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Drawing.Renderer +{ + internal class ShapeRenderer : DrawingRenderer + { + /// + /// Calculated shape textbox + /// + RectRenderItem InsetTextBox; + + RectRenderItem MarginTextBox; + + /// + /// Textbox from memory + /// + public DrawingTextBody TextBody{ get; internal set; } + + //public ShapeRenderer(eShapeStyle style, double top, double left, double width, double height, eTextAutofit autofit) : base() + //{ + // var parentBounds = new BoundingBox(top, left, width, height); + // var shapeGroup = new GroupRenderItem(parentBounds); + + //} + + public ShapeRenderer(ExcelShape shape) : base(shape) + { + var style = shape.Style; + + var parentBounds = shape.GetBoundingBox(); + var shapeGroup = new GroupRenderItem(parentBounds, shape.Rotation); + RenderItems.Add(shapeGroup); + + if (style==eShapeStyle.CustomShape) + { + foreach (var path in shape.CustomGeom.DrawingPaths) + { + shapeGroup.RenderItems.Add(AddFromPaths(Bounds, path)); + } + } + else + { + var shapeDef = PresetShapeDefinitions.ShapeDefinitions[(ShapeStyle)style].Clone(); + if (shape.HasCustomAdjustmentPoints()) + { + shapeDef.Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, shape.GetAdjustmentPointsNames().ToList(), shape.GetAdjustmentPointsList().ToList()); + } + else + { + shapeDef.Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); + } + + //Draw Filled path's + foreach (var path in shapeDef.ShapePaths) + { + if (path.Fill != PathFillMode.None) + { + shapeGroup.RenderItems.Add(AddFromPaths(parentBounds, path, true, false)); + } + } + + //Draw border path's + foreach (var path in shapeDef.ShapePaths) + { + if (path.Stroke) + { + shapeGroup.RenderItems.Add(AddFromPaths(parentBounds, path, false, true)); + } + } + + if (shape.Text != null) + { + if (shapeDef.TextBoxRect != null) + { + InsetTextBox = new RectRenderItem(Bounds); + InsetTextBox.Bounds.Left = (float)shapeDef.TextBoxRect.LeftValue.PixelToPoint(); + InsetTextBox.Bounds.Top = (float)shapeDef.TextBoxRect.TopValue.PixelToPoint(); + InsetTextBox.Bounds.Left = (float)shapeDef.TextBoxRect.LeftValue.PixelToPoint(); + InsetTextBox.Bounds.Top = (float)shapeDef.TextBoxRect.TopValue.PixelToPoint(); + InsetTextBox.FillOpacity = 0.3d; + + if (shape.TextBody.TextAutofit != eTextAutofit.ShapeAutofit) + { + InsetTextBox.Width = ((double)((float)shapeDef.TextBoxRect.RightValue - (float)shapeDef.TextBoxRect.LeftValue)).PixelToPoint(); + InsetTextBox.Height = ((double)((float)shapeDef.TextBoxRect.BottomValue - (float)shapeDef.TextBoxRect.TopValue)).PixelToPoint(); + InsetTextBox.Width = ((double)((float)shapeDef.TextBoxRect.RightValue - (float)shapeDef.TextBoxRect.LeftValue)).PixelToPoint(); + InsetTextBox.Height = ((double)((float)shapeDef.TextBoxRect.BottomValue - (float)shapeDef.TextBoxRect.TopValue)).PixelToPoint(); + } + else + { + InsetTextBox.Width = (float)shapeDef.TextBoxRect.RightValue.PixelToPoint(); + InsetTextBox.Height = (float)shapeDef.TextBoxRect.BottomValue.PixelToPoint(); + InsetTextBox.Width = (float)shapeDef.TextBoxRect.RightValue.PixelToPoint(); + InsetTextBox.Height = (float)shapeDef.TextBoxRect.BottomValue.PixelToPoint(); + } + } + else + { + InsetTextBox = null; + } + + InsetTextBox.FillOpacity = 0.3d; + + TextBody = CreateTextBodyItem(shape.TextBody); + } + } + } + + protected RenderItem AddFromPaths(BoundingBox parent, DrawingPath path, bool drawFill = true, bool drawBorder = true) + { + var pi = new PathRenderItem(parent); + var coordinates = new List(); + PathCommands cmd = null; + PathsBase pCmd = null; + double cx = 0, cy = 0; + foreach (var p in path.Paths) + { + switch (p.Type) + { + case PathDrawingType.MoveTo: + AddCmd(pi, path, coordinates, ref cmd, pCmd, p, PathCommandType.Move); + break; + case PathDrawingType.LineTo: + AddCmd(pi, path, coordinates, ref cmd, pCmd, p, PathCommandType.Line); + break; + case PathDrawingType.CubicBezierTo: + AddCmd(pi, path, coordinates, ref cmd, pCmd, p, PathCommandType.CubicBézier); + break; + case PathDrawingType.QuadBezierTo: + AddCmd(pi, path, coordinates, ref cmd, pCmd, p, PathCommandType.QuadraticBézier); + break; + case PathDrawingType.ArcTo: + SetCmdCoordinats(cmd, p, coordinates); + AddArc(pi, path, coordinates, pCmd, out cx, out cy, p); + cmd = null; + break; + case PathDrawingType.Close: + if (pi.Commands[pi.Commands.Count - 1].Type != PathCommandType.Arc) + { + pi.Commands[pi.Commands.Count - 1].Coordinates = coordinates.ToArray(); + coordinates.Clear(); + } + pi.Commands.Add(new PathCommands(PathCommandType.End)); + cmd = null; + break; + } + //p.TranslateCoordiantesToPointsAndDegrees(ExcelDrawing.EMU_PER_POINT, 1); + pCmd = p; + } + if (coordinates.Count > 0) + { + pi.Commands[pi.Commands.Count - 1].Coordinates = coordinates.ToArray(); + } + var shape = (ExcelShape)Drawing; + if (drawFill) + { + pi.FillColorSource = path.Fill; + pi.SetDrawingPropertiesFill(Theme, shape.Fill, shape.ThemeStyles.FillReference.Color); + } + else + { + pi.FillColorSource = PathFillMode.None; + pi.FillColor = "none"; + } + + if (drawBorder) + { + pi.BorderColorSource = path.Stroke ? PathFillMode.Norm : PathFillMode.None; + pi.SetDrawingPropertiesBorder(Theme, shape.Border, shape.ThemeStyles.BorderReference.Color, path.Stroke); + } + else + { + pi.BorderColorSource = PathFillMode.None; + pi.BorderColor = "none"; + } + + return pi; + } + public string ViewBox + { + get + { + double l=0, t=0, r=1, b=1; + foreach(var item in RenderItems) + { + item.GetBounds(out var il, out var it, out var ir, out var ib); + if(ilr) + { + r = ir; + } + if(ib>b) + { + b = ib; + } + } + return $"{(Bounds.Left).PointToPixelString()},{Bounds.Top.PointToPixelString()},{Bounds.Right.PointToPixelString()},{Bounds.Bottom.PointToPixelString()}"; + } + } + DrawingTextBody CreateTextBodyItem(ExcelTextBody bodyOrig) + { + if (InsetTextBox == null) + { + GetShapeInnerBound(out double x, out double y, out double width, out double height); + InsetTextBox = new RectRenderItem(Bounds); + InsetTextBox.Bounds.Left = x.PixelToPoint(); + InsetTextBox.Bounds.Top = y.PixelToPoint(); + InsetTextBox.Width = width.PixelToPoint(); + InsetTextBox.Height = height.PixelToPoint(); + //InsetTextBox.Bounds.Parent = RenderTextbox.Parent; //TODO:Check that textBody is correct. + InsetTextBox.Bounds.Left = x.PixelToPoint(); + InsetTextBox.Bounds.Top = y.PixelToPoint(); + InsetTextBox.Width = width.PixelToPoint(); + InsetTextBox.Height = height.PixelToPoint(); + //InsetTextBox.Bounds.Parent = RenderTextbox.Parent; //TODO:Check that textBody is correct. + } + + double l, r, t, b; + bodyOrig.GetInsetsOrDefaults(out l, out t, out r, out b); + + MarginTextBox = new RectRenderItem(this.Bounds); + + MarginTextBox.Top = t + InsetTextBox.Top; + MarginTextBox.Left = l + InsetTextBox.Left; + MarginTextBox.Width = InsetTextBox.Width - r - l; + MarginTextBox.Height = InsetTextBox.Height - b - t; + + var grp = new GroupRenderItem(MarginTextBox.Bounds); + RenderItems.Add(grp); + + var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, MarginTextBox.Left, MarginTextBox.Top, MarginTextBox.Width, MarginTextBox.Height); + txtBodyItem.ImportTextBodyAndParagraphs(bodyOrig); + + txtBodyItem.AppendRenderItems(grp.RenderItems); + + //ChartAreaRenderItems.Add(new SvgEndGroupItem(this, Bounds)); + + return txtBodyItem; + } + + //private void RenderText(StringBuilder sb) + //{ + // //RenderDebugTextBox(sb); + // textBody.Render(sb); + //} + + //private void RenderDebugTextBox(StringBuilder sb) + //{ + // InsetTextBox.FillOpacity = 0.3d; + // InsetTextBox.FillColor = "green"; + // InsetTextBox.Render(sb); + + // MarginTextBox.FillColor = "red"; + // MarginTextBox.FillOpacity = 0.3; + // MarginTextBox.Render(sb); + // //InsetTextBox.GetBounds(out double l, out double t, out double r, out double b); + + // //var area = textBody.Bounds; + + // ////Temporarily set as child bounds + // //insetTextBox.Bounds.Left = (float)area.Left + l; + // //insetTextBox.Bounds.Top = (float)area.Top + t; + // //insetTextBox.Bounds.Width = (float)area.Width; + // //insetTextBox.Bounds.Height = (float)area.Height; + + // //insetTextBox.FillColor = "blue"; + + // ////Render the inner area + // //insetTextBox.Render(sb); + + // ////Reset variables so that the rendering of children later aren't affected + // //insetTextBox.Bounds.Left = l; + // //insetTextBox.Bounds.Top = t; + // //insetTextBox.Bounds.Right = r; + // //insetTextBox.Bounds.Bottom = b; + //} + + private void GetShapeInnerBound(out double x, out double y, out double width, out double height) + { + double currentX = 0, currentY = 0, xe, ye; + x = y = 0; + width = xe = Bounds.Width; + height = ye = Bounds.Height; + foreach (var ri in RenderItems) + { + switch (ri.Type) + { + case RenderItemType.Rect: + var rectItem = (RectRenderItem)ri; + x = rectItem.Left; + y = rectItem.Top; + width = rectItem.Width; + height = rectItem.Height; + break; + case RenderItemType.Path: + var pathItem = (PathRenderItem)ri; + foreach (var cmd in pathItem.Commands) + { + var cmdCoordinates = new List(); + for (int i = 0; i < cmd.Coordinates.Length; i++) + { + switch (cmd.Type) + { + case PathCommandType.Move: + if (i == 0) + { + currentX = cmd.Coordinates[i]; + currentY = cmd.Coordinates[++i]; + } + else + { + HandleLine(ref currentX, ref currentY, ref xe, ref ye, cmd, cmdCoordinates, ref i); + } + break; + case PathCommandType.VerticalLine: + HandleVertical(y, ref currentY, ref xe, cmd.Coordinates[i]); + break; + case PathCommandType.HorizontalLine: + HandleHorizontal(x, ref currentX, ref xe, cmd.Coordinates[i]); + break; + case PathCommandType.Line: + HandleLine(ref currentX, ref currentY, ref xe, ref ye, cmd, cmdCoordinates, ref i); + break; + case PathCommandType.CubicBézier: + if (currentX > x) + { + x = currentX; + } + if (currentY > y) + { + y = currentY; + } + i += 4; + break; + + } + } + } + break; + } + } + if (xe != double.MinValue) + { + width = xe - x; + } + if (ye != double.MinValue) + { + height = ye - y; + } + } + + private static void HandleLine(ref double currentX, ref double currentY, ref double xe, ref double ye, PathCommands cmd, List cmdCoordinates, ref int i) + { + xe = cmd.Coordinates[i]; + ye = cmd.Coordinates[++i]; + if (xe == currentX || ye == currentY) + { + if (cmdCoordinates.Count == 0) + { + cmdCoordinates.Add(new Coordinate(currentX, currentY)); + } + cmdCoordinates.Add(new Coordinate(xe, ye)); + } + else + { + var w = Math.Abs(xe - currentX); + var h = Math.Abs(ye - currentY); + cmdCoordinates.Add(new Coordinate((Math.Min(xe, currentX) + w) / 2, (Math.Min(ye, currentY) + h) / 2)); + } + currentX = xe; + currentY = ye; + } + + + private static void HandleVertical(double y, ref double currentY, ref double ye, double yec) + { + if (currentY < y || currentY == double.MinValue) + { + currentY = y; + } + if (ye > yec || ye == double.MinValue) + { + ye = yec; + } + } + private static void HandleHorizontal(double x, ref double currentX, ref double xe, double xec) + { + if (currentX < x || currentX == double.MinValue) + { + currentX = x; + } + if (xe > xec || xe == double.MinValue) + { + xe = xec; + } + } + protected static void AddCmd(PathRenderItem pi, DrawingPath path, List coordinates, ref PathCommands cmd, PathsBase pp, PathsBase p, PathCommandType commandType) + { + if (pp == null || pp.Type != p.Type) + { + SetCmdCoordinats(cmd, p, coordinates); + cmd = new PathCommands(commandType); + pi.Commands.Add(cmd); + } + AddToCoordinates(path, coordinates, p); + } + protected static void AddArc(PathRenderItem pi, DrawingPath path, List coordinates, PathsBase pCmd, out double startPointX, out double startPointY, PathsBase p) + { + //var width = ((double)path.Width.Value / ExcelDrawing.EMU_PER_PIXEL); + //var height = ((double)path.Height.Value / ExcelDrawing.EMU_PER_PIXEL); + var arc = (ArcTo)p; + PathCommands c = null; + startPointX = pCmd.EndX; + startPointY = pCmd.EndY; + if (startPointX != 0) startPointX /= ExcelDrawing.EMU_PER_POINT; + if (startPointY != 0) startPointY /= ExcelDrawing.EMU_PER_POINT; + var wR = arc.WidthRadius.Value / ExcelDrawing.EMU_PER_POINT; + var hR = arc.HeightRadius.Value / ExcelDrawing.EMU_PER_POINT; + if (wR == 0 && hR == 0) + { + return; + } + var stA = arc.StartAngle.Value / 60000d; + var swA = arc.SwingAngle.Value / 60000d; + + while (swA != 0) + { + var aAdd = swA < 0 ? Math.Max(swA, -180) : Math.Min(swA, 180); + var endAngle = AngleToRadians(stA + aAdd); + + var stA_Adj = stA < 0 ? (stA + 360) % 360 : stA; + var adjRads = AngleToRadians(stA_Adj); + + //Start and End angles are NOT the 't' angle of the equations we use. + //The angles we are given are DIRECTLY against the ellipse. Or point 'P' in a parametric form + //Therefore we have to use the angle we have to calculate the angles needed for our formulas. + var angleT = Math.Atan((wR * Math.Tan(adjRads)) / hR); + var angleTEnd = Math.Atan((wR * Math.Tan(endAngle)) / hR); + + //Atan can only return values on positive x 90° to -90° + //So we must adjust by adding Pi (180°) if x of the angle is negative + if (Math.Cos(adjRads) < 0) + { + angleT += (Math.Round((double)System.Math.PI, 14)); + } + if (Math.Cos(endAngle) < 0) + { + angleTEnd += (Math.Round((double)System.Math.PI, 14)); + } + + var centerX = startPointX - (wR * Math.Cos(angleT)); + var centerY = startPointY - (hR * Math.Sin(angleT)); + var endX = (double)centerX + (wR * Math.Cos(angleTEnd)); + var endY = (double)centerY + (hR * Math.Sin(angleTEnd)); + c = new PathCommands(PathCommandType.Arc, wR, hR, 0, 0, swA < 0 ? 0 : 1, endX, endY); + pi.Commands.Add(c); + stA += aAdd; + swA -= aAdd; + if (wR != 0) + { + startPointX = endX; + } + if (hR != 0) + { + startPointY = endY; + } + ((ArcTo)p).SetEndCoordinates(endX * ExcelDrawing.EMU_PER_POINT, endY * ExcelDrawing.EMU_PER_POINT); + } + } + + protected static double AngleToRadians(double angle) + { + return MConverter.DegreesToRadians(angle); + } + protected static void SetCmdCoordinats(PathCommands cmd, PathsBase p, List coordinates) + { + if (cmd != null) + { + cmd.Coordinates = coordinates.ToArray(); + if (cmd.Coordinates.Length > 0) + { + coordinates.Clear(); + } + } + } + private static void AddToCoordinates(DrawingPath path, List coordinates, PathsBase p) + { + var mt = (PathWithCoordinates)p; + foreach (var c in mt.Coordinates) + { + coordinates.Add(c.X.Value / ExcelDrawing.EMU_PER_POINT); + coordinates.Add(c.Y.Value / ExcelDrawing.EMU_PER_POINT); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Shape/ShapeGuidePoint.cs b/src/EPPlus/Drawing/Shape/ShapeGuidePoint.cs index 968ee3d484..363d319d01 100644 --- a/src/EPPlus/Drawing/Shape/ShapeGuidePoint.cs +++ b/src/EPPlus/Drawing/Shape/ShapeGuidePoint.cs @@ -14,6 +14,15 @@ namespace OfficeOpenXml.Drawing.Shape { internal class ShapeGuidePoint { + public static implicit operator ShapeGuidePoint(int value) + { + return new ShapeGuidePoint(value); + } + public static implicit operator int(ShapeGuidePoint value) + { + return value.Value; + } + internal static string valuePrefix = "val "; private int _value; internal string fmlaValue @@ -23,7 +32,7 @@ private set { } } internal int Value { - private get { return _value; } + get { return _value; } set { _value = value; } } diff --git a/src/EPPlus/Drawing/Shape/ShapeGuidesFactory.cs b/src/EPPlus/Drawing/Shape/ShapeGuidesFactory.cs index bfbd0d7b24..0b7900f288 100644 --- a/src/EPPlus/Drawing/Shape/ShapeGuidesFactory.cs +++ b/src/EPPlus/Drawing/Shape/ShapeGuidesFactory.cs @@ -11,601 +11,736 @@ Date Author Change 01/01/2025 EPPlus Software AB Initial release EPPlus 8 *************************************************************************************************/ using System.Collections.Generic; +using System.Linq; namespace OfficeOpenXml.Drawing.Shape { internal static class ShapeGuidesFactory { + internal static Dictionary> DefaultAdjustments = new Dictionary> + { + {eShapeStyle.Parallelogram,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.Trapezoid,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.RoundRect,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.Octagon,new Dictionary { {"adj", 29289}}}, + {eShapeStyle.Triangle,new Dictionary { {"adj", 50000}}}, + {eShapeStyle.Hexagon,new Dictionary { {"adj", 25000},{"vf", 115470}}}, + {eShapeStyle.Plus,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.Pentagon,new Dictionary { {"hf", 105146},{"vf", 110557}}}, + {eShapeStyle.Can,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.Cube,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.Bevel,new Dictionary { {"adj", 12500}}}, + {eShapeStyle.FoldedCorner,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.SmileyFace,new Dictionary { {"adj", 4653}}}, + {eShapeStyle.Donut,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.NoSmoking,new Dictionary { {"adj", 18750}}}, + {eShapeStyle.BlockArc,new Dictionary { {"adj1", 18000000},{"adj2", 0},{"adj3", 25000}}}, + {eShapeStyle.Sun,new Dictionary { {"adj", 25000}}}, + {eShapeStyle.Moon,new Dictionary { {"adj", 50000}}}, + {eShapeStyle.Arc,new Dictionary { {"adj1", 16200000 },{"adj2", 0}}}, + {eShapeStyle.BracketPair,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.BracePair,new Dictionary { {"adj", 8333}}}, + {eShapeStyle.Plaque,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.LeftBracket,new Dictionary { {"adj", 8333}}}, + {eShapeStyle.RightBracket,new Dictionary { {"adj", 8333}}}, + {eShapeStyle.LeftBrace,new Dictionary { {"adj1", 8333},{"adj2", 50000}}}, + {eShapeStyle.RightBrace,new Dictionary { {"adj1", 8333},{"adj2", 50000}}}, + {eShapeStyle.RightArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.LeftArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.UpArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.DownArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.LeftRightArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.UpDownArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.QuadArrow,new Dictionary { {"adj1", 22500},{"adj2", 22500},{"adj3", 22500}}}, + {eShapeStyle.LeftRightUpArrow,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000}}}, + {eShapeStyle.BentArrow,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 43750}}}, + {eShapeStyle.UturnArrow,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 43750},{"adj5", 75000}}}, + {eShapeStyle.LeftUpArrow,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000}}}, + {eShapeStyle.BentUpArrow,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000}}}, + {eShapeStyle.CurvedRightArrow,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 25000}}}, + {eShapeStyle.CurvedLeftArrow,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 25000}}}, + {eShapeStyle.CurvedUpArrow,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 25000}}}, + {eShapeStyle.CurvedDownArrow,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 25000}}}, + {eShapeStyle.StripedRightArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.NotchedRightArrow,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.HomePlate,new Dictionary { {"adj", 50000}}}, + {eShapeStyle.Chevron,new Dictionary { {"adj", 50000}}}, + {eShapeStyle.RightArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 64977}}}, + {eShapeStyle.LeftArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 649767}}}, + {eShapeStyle.UpArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 649767}}}, + {eShapeStyle.DownArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 649767}}}, + {eShapeStyle.LeftRightArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 48123}}}, + {eShapeStyle.UpDownArrowCallout,new Dictionary { {"adj1", 25000},{"adj2", 25000},{"adj3", 25000},{"adj4", 48123}}}, + {eShapeStyle.QuadArrowCallout,new Dictionary { {"adj1", 18515},{"adj2", 18515},{"adj3", 18515},{"adj4", 48123}}}, + {eShapeStyle.CircularArrow,new Dictionary { {"adj1", 12500},{"adj2", 1903865},{"adj3", -1903865},{"adj4", 18000000},{"adj5", 12500}}}, + {eShapeStyle.Star4,new Dictionary { {"adj", 12500}}}, + {eShapeStyle.Star5,new Dictionary { {"adj", 19098},{"hf", 105146},{"vf", 110557}}}, + {eShapeStyle.Star8,new Dictionary { {"adj", 37500}}}, + {eShapeStyle.Star16,new Dictionary { {"adj", 37500}}}, + {eShapeStyle.Star24,new Dictionary { {"adj", 37500}}}, + {eShapeStyle.Star32,new Dictionary { {"adj", 37500}}}, + {eShapeStyle.Ribbon2,new Dictionary { {"adj1", 16667},{"adj2", 50000}}}, + {eShapeStyle.Ribbon,new Dictionary { {"adj1", 16667},{"adj2", 50000}}}, + {eShapeStyle.EllipseRibbon2,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 12500}}}, + {eShapeStyle.EllipseRibbon,new Dictionary { {"adj1", 25000},{"adj2", 50000},{"adj3", 12500}}}, + {eShapeStyle.VerticalScroll,new Dictionary { {"adj", 12500}}}, + {eShapeStyle.HorizontalScroll,new Dictionary { {"adj", 12500}}}, + {eShapeStyle.Wave,new Dictionary { {"adj1", 12500},{"adj2", 0}}}, + {eShapeStyle.DoubleWave,new Dictionary { {"adj1", 6250},{"adj2", 0}}}, + {eShapeStyle.WedgeRectCallout,new Dictionary { {"adj1", -20833},{"adj2", 62500}}}, + {eShapeStyle.WedgeRoundRectCallout,new Dictionary { {"adj1", -20833},{"adj2", 62500},{"adj3", 16667}}}, + {eShapeStyle.WedgeEllipseCallout,new Dictionary { {"adj1", -20833},{"adj2", 62500}}}, + {eShapeStyle.CloudCallout,new Dictionary { {"adj1", -20833},{"adj2", 62500}}}, + {eShapeStyle.BorderCallout1,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 112500},{"adj4", -38333},{"adj5", 18750},{"adj6", -8333},{"adj7", 112500},{"adj8", -38333},{"adj9", 18750},{"adj10", -8333},{"adj11", 112500},{"adj12", -38333}}}, + {eShapeStyle.BorderCallout2,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 112500},{"adj6", -46667}}}, + {eShapeStyle.BorderCallout3,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 100000},{"adj6", -16667},{"adj7", 112963},{"adj8", -8333}}}, + {eShapeStyle.AccentCallout1,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 112500},{"adj4", -38333}}}, + {eShapeStyle.AccentCallout2,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 112500},{"adj6", -46667}}}, + {eShapeStyle.AccentCallout3,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 100000},{"adj6", -16667},{"adj7", 112963},{"adj8", -8333}}}, + {eShapeStyle.Callout1,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 112500},{"adj4", -38333},{"adj5", 18750},{"adj6", -8333},{"adj7", 112500},{"adj8", -38333},{"adj9", 18750},{"adj10", -8333},{"adj11", 112500},{"adj12", -38333}}}, + {eShapeStyle.Callout2,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 112500},{"adj6", -46667}}}, + {eShapeStyle.Callout3,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 100000},{"adj6", -16667},{"adj7", 112963},{"adj8", -8333}}}, + {eShapeStyle.AccentBorderCallout1,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 112500},{"adj4", -38333}}}, + {eShapeStyle.AccentBorderCallout2,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 112500},{"adj6", -46667}}}, + {eShapeStyle.AccentBorderCallout3,new Dictionary { {"adj1", 18750},{"adj2", -8333},{"adj3", 18750},{"adj4", -16667},{"adj5", 100000},{"adj6", -16667},{"adj7", 112963},{"adj8", -8333}}}, + {eShapeStyle.LeftRightRibbon,new Dictionary { {"adj1", 50000},{"adj2", 50000},{"adj3", 16667}}}, + {eShapeStyle.DiagStripe,new Dictionary { {"adj", 50000}}}, + {eShapeStyle.Pie,new Dictionary { {"adj1", 0},{"adj2", -9000000}}}, + {eShapeStyle.NonIsoscelesTrapezoid,new Dictionary { {"adj1", 25000},{"adj2", 25000}}}, + {eShapeStyle.Decagon,new Dictionary { {"vf", 105146}}}, + {eShapeStyle.Heptagon,new Dictionary { {"hf", 102572},{"vf", 105210}}}, + {eShapeStyle.Star6,new Dictionary { {"adj", 28868},{"hf", 115470}}}, + {eShapeStyle.Star7,new Dictionary { {"adj", 34601},{"hf", 102572},{"vf", 105210}}}, + {eShapeStyle.Star10,new Dictionary { {"adj", 42533},{"hf", 105146}}}, + {eShapeStyle.Star12,new Dictionary { {"adj", 37500}}}, + {eShapeStyle.Round1Rect,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.Round2SameRect,new Dictionary { {"adj1", 16667},{"adj2", 0}}}, + {eShapeStyle.Round2DiagRect,new Dictionary { {"adj1", 16667},{"adj2", 0}}}, + {eShapeStyle.SnipRoundRect,new Dictionary { {"adj1", 16667},{"adj2", 16667}}}, + {eShapeStyle.Snip1Rect,new Dictionary { {"adj", 16667}}}, + {eShapeStyle.Snip2SameRect,new Dictionary { {"adj1", 16667},{"adj2", 0}}}, + {eShapeStyle.Snip2DiagRect,new Dictionary { {"adj1", 0},{"adj2", 16667}}}, + {eShapeStyle.Frame,new Dictionary { {"adj1", 12500}}}, + {eShapeStyle.HalfFrame,new Dictionary { {"adj1", 33333},{"adj2", 33333}}}, + {eShapeStyle.Teardrop,new Dictionary { {"adj", 100000}}}, + {eShapeStyle.Chord,new Dictionary { {"adj1", 4500000},{"adj2", -9000000}}}, + {eShapeStyle.Corner,new Dictionary { {"adj1", 50000},{"adj2", 50000}}}, + {eShapeStyle.MathPlus,new Dictionary { {"adj1", 23520}}}, + {eShapeStyle.MathMinus,new Dictionary { {"adj1", 23520}}}, + {eShapeStyle.MathMultiply,new Dictionary { {"adj1", 23520}}}, + {eShapeStyle.MathDivide,new Dictionary { {"adj1", 23520},{"adj2", 5880},{"adj3", 11760}}}, + {eShapeStyle.MathEqual,new Dictionary { {"adj1", 23520},{"adj2", 11760}}}, + {eShapeStyle.MathNotEqual,new Dictionary { {"adj1", 23520},{"adj2", 11000000},{"adj3", 11760}}}, + {eShapeStyle.Gear6,new Dictionary { {"adj1", 15000},{"adj2", 3526}}}, + {eShapeStyle.Gear9,new Dictionary { {"adj1", 10000},{"adj2", 1763}}}, + {eShapeStyle.LeftCircularArrow,new Dictionary { {"adj1", 12500},{"adj2", -1903865},{"adj3", 1903865},{"adj4", 18000000},{"adj5", 12500}}}, + {eShapeStyle.LeftRightCircularArrow,new Dictionary { {"adj1", 12500},{"adj2", 1903865},{"adj3", -1903865},{"adj4", -16096130},{"adj5", 12500}}}, + {eShapeStyle.SwooshArrow,new Dictionary { {"adj1", 25000},{"adj2", 16667}}}, + }; + internal static Dictionary GetAdjustmentPoints(eShapeStyle style) { - return style switch + if(DefaultAdjustments.TryGetValue(style, out Dictionary points)) + { + return points; + } + return null; + } + public static List GetAdjustmentPointList(eShapeStyle style) + { + if (DefaultAdjustments.TryGetValue(style, out Dictionary points)) { - eShapeStyle.BentConnector3 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.CurvedConnector3 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.RoundRect => new Dictionary - { - { "adj", new ShapeGuidePoint(25000 /*50000-50000*/) } - }, - eShapeStyle.Snip1Rect => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Snip2SameRect => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Snip2DiagRect => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.SnipRoundRect => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Round1Rect => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Round2SameRect => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Round2DiagRect => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Triangle => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) /*50000-1000000*/ } - }, - eShapeStyle.Parallelogram => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Trapezoid => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Hexagon => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) }, - { "vf", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Octagon => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Pie => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Chord => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Teardrop => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Frame => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.HalfFrame => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Corner => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.DiagStripe => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Plus => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Plaque => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Can => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Cube => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Bevel => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Donut => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.NoSmoking => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.BlockArc => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.FoldedCorner => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.SmileyFace => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Sun => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Moon => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Arc => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BracketPair => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.BracePair => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.LeftBracket => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.RightBracket => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.LeftBrace => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.RightBrace => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.RightArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.UpArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.DownArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftRightArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.UpDownArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.QuadArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftRightUpArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BentArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.UturnArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftUpArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BentUpArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CurvedRightArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CurvedLeftArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CurvedUpArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CurvedDownArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.StripedRightArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.NotchedRightArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.HomePlate => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Chevron => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.RightArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.DownArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.UpArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.LeftRightArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.QuadArrowCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CircularArrow => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.MathPlus => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.MathMinus => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.MathMultiply => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.MathDivide => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.MathEqual => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.MathNotEqual => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Star4 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Star5 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) }, - { "hf", new ShapeGuidePoint(50000) }, - { "vf", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Star6 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) }, - { "hf", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Star7 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) }, - { "hf", new ShapeGuidePoint(50000) }, - { "vf", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Star8 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Star10 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) }, - { "hf", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Star12 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Star16 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Star24 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Star32 => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Ribbon2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Ribbon => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.EllipseRibbon2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.EllipseRibbon => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.VerticalScroll => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.HorizontalScroll => new Dictionary - { - { "adj", new ShapeGuidePoint(50000) } - }, - eShapeStyle.Wave => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.DoubleWave => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.WedgeRectCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.WedgeRoundRectCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.WedgeEllipseCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.CloudCallout => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BorderCallout1 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BorderCallout2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.BorderCallout3 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - { "adj7", new ShapeGuidePoint(50000) }, - { "adj8", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentCallout1 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentCallout2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentCallout3 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - { "adj7", new ShapeGuidePoint(50000) }, - { "adj8", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Callout1 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Callout2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.Callout3 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - { "adj7", new ShapeGuidePoint(50000) }, - { "adj8", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentBorderCallout1 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentBorderCallout2 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - }, - eShapeStyle.AccentBorderCallout3 => new Dictionary - { - { "adj1", new ShapeGuidePoint(50000) }, - { "adj2", new ShapeGuidePoint(50000) }, - { "adj3", new ShapeGuidePoint(50000) }, - { "adj4", new ShapeGuidePoint(50000) }, - { "adj5", new ShapeGuidePoint(50000) }, - { "adj6", new ShapeGuidePoint(50000) }, - { "adj7", new ShapeGuidePoint(50000) }, - { "adj8", new ShapeGuidePoint(50000) }, - }, - _ => null - }; + return points.Select(x => x.Value.Value).ToList(); ; + } + return new List(); } + //return style switch + //{ + // eShapeStyle.BentConnector3 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.CurvedConnector3 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.RoundRect => new Dictionary + // { + // { "adj", new ShapeGuidePoint(25000 /*50000-50000*/) } + // }, + // eShapeStyle.Snip1Rect => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Snip2SameRect => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Snip2DiagRect => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.SnipRoundRect => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Round1Rect => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Round2SameRect => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Round2DiagRect => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Triangle => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) /*50000-1000000*/ } + // }, + // eShapeStyle.Parallelogram => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Trapezoid => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Hexagon => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) }, + // { "vf", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Octagon => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Pie => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Chord => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Teardrop => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Frame => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.HalfFrame => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Corner => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.DiagStripe => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Plus => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Plaque => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Can => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Cube => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Bevel => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Donut => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.NoSmoking => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.BlockArc => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.FoldedCorner => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.SmileyFace => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Sun => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Moon => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Arc => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BracketPair => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.BracePair => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.LeftBracket => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.RightBracket => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.LeftBrace => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.RightBrace => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.RightArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.UpArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.DownArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftRightArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.UpDownArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.QuadArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftRightUpArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BentArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.UturnArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftUpArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BentUpArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CurvedRightArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CurvedLeftArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CurvedUpArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CurvedDownArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.StripedRightArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.NotchedRightArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.HomePlate => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Chevron => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.RightArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.DownArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.UpArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.LeftRightArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.QuadArrowCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CircularArrow => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.MathPlus => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.MathMinus => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.MathMultiply => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.MathDivide => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.MathEqual => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.MathNotEqual => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Star4 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Star5 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) }, + // { "hf", new ShapeGuidePoint(50000) }, + // { "vf", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Star6 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) }, + // { "hf", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Star7 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) }, + // { "hf", new ShapeGuidePoint(50000) }, + // { "vf", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Star8 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Star10 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) }, + // { "hf", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Star12 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Star16 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Star24 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Star32 => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Ribbon2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Ribbon => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.EllipseRibbon2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.EllipseRibbon => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.VerticalScroll => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.HorizontalScroll => new Dictionary + // { + // { "adj", new ShapeGuidePoint(50000) } + // }, + // eShapeStyle.Wave => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.DoubleWave => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.WedgeRectCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.WedgeRoundRectCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.WedgeEllipseCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.CloudCallout => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BorderCallout1 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BorderCallout2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.BorderCallout3 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // { "adj7", new ShapeGuidePoint(50000) }, + // { "adj8", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentCallout1 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentCallout2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentCallout3 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // { "adj7", new ShapeGuidePoint(50000) }, + // { "adj8", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Callout1 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Callout2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.Callout3 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // { "adj7", new ShapeGuidePoint(50000) }, + // { "adj8", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentBorderCallout1 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentBorderCallout2 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // }, + // eShapeStyle.AccentBorderCallout3 => new Dictionary + // { + // { "adj1", new ShapeGuidePoint(50000) }, + // { "adj2", new ShapeGuidePoint(50000) }, + // { "adj3", new ShapeGuidePoint(50000) }, + // { "adj4", new ShapeGuidePoint(50000) }, + // { "adj5", new ShapeGuidePoint(50000) }, + // { "adj6", new ShapeGuidePoint(50000) }, + // { "adj7", new ShapeGuidePoint(50000) }, + // { "adj8", new ShapeGuidePoint(50000) }, + // }, + // _ => null + //}; } -} \ No newline at end of file +} diff --git a/src/EPPlus/Drawing/Slicer/ExcelSlicer.cs b/src/EPPlus/Drawing/Slicer/ExcelSlicer.cs index 1438726d62..bf2975d2d2 100644 --- a/src/EPPlus/Drawing/Slicer/ExcelSlicer.cs +++ b/src/EPPlus/Drawing/Slicer/ExcelSlicer.cs @@ -256,12 +256,12 @@ internal override void DeleteMe() internal override void SaveDrawing(bool hasLoadedPivotTables) { base.SaveDrawing(hasLoadedPivotTables); - if (Cache is ExcelTableSlicerCache) + if (Cache is ExcelTableSlicerCache) { Cache.SlicerCacheXml.PreserveWhitespace = true; Cache.SlicerCacheXml.Save(Cache.Part.GetStream(FileMode.Create, FileAccess.Write)); } - else if (Cache is ExcelPivotTableSlicerCache p) + else if(Cache is ExcelPivotTableSlicerCache p) { if (Cache == null) return; if (hasLoadedPivotTables) diff --git a/src/EPPlus/Drawing/Style/Coloring/ExcelColorTransformSimpleItem.cs b/src/EPPlus/Drawing/Style/Coloring/ExcelColorTransformSimpleItem.cs index bbd53c1c7c..cf2e59724a 100644 --- a/src/EPPlus/Drawing/Style/Coloring/ExcelColorTransformSimpleItem.cs +++ b/src/EPPlus/Drawing/Style/Coloring/ExcelColorTransformSimpleItem.cs @@ -18,7 +18,7 @@ namespace OfficeOpenXml.Drawing.Style.Coloring internal class ExcelColorTransformSimpleItem : IColorTransformItem, ISource { /// - /// Type of tranformation + /// BulletType of tranformation /// public eColorTransformType Type { get; set; } diff --git a/src/EPPlus/Drawing/Style/Coloring/ExcelDrawingThemeColorManager.cs b/src/EPPlus/Drawing/Style/Coloring/ExcelDrawingThemeColorManager.cs index 2a01f9176e..84ab4ef526 100644 --- a/src/EPPlus/Drawing/Style/Coloring/ExcelDrawingThemeColorManager.cs +++ b/src/EPPlus/Drawing/Style/Coloring/ExcelDrawingThemeColorManager.cs @@ -13,7 +13,7 @@ Date Author Change using System.Drawing; using System.Xml; using System; - +using System.Linq; namespace OfficeOpenXml.Drawing.Style.Coloring { /// @@ -118,10 +118,6 @@ private bool IsTopNodeColorNode(XmlNode topNode) /// /// public eDrawingColorType ColorType { get; internal protected set; } = eDrawingColorType.None; - internal void SetXml(XmlNamespaceManager nameSpaceManager, XmlNode node) - { - - } ExcelColorTransformCollection _transforms = null; /// /// Color transformations @@ -140,27 +136,27 @@ public ExcelColorTransformCollection Transforms } /// /// A rgb color. - /// This property has a value when Type is set to Rgb + /// This property has a value when BulletType is set to Rgb /// public ExcelDrawingRgbColor RgbColor { get; private set; } /// - /// A rgb precentage color. - /// This property has a value when Type is set to RgbPercentage + /// A rgb percentage color. + /// This property has a value when BulletType is set to RgbPercentage /// public ExcelDrawingRgbPercentageColor RgbPercentageColor { get; private set; } /// /// A hsl color. - /// This property has a value when Type is set to Hsl + /// This property has a value when BulletType is set to Hsl /// public ExcelDrawingHslColor HslColor { get; private set; } /// /// A preset color. - /// This property has a value when Type is set to Preset + /// This property has a value when BulletType is set to Preset /// public ExcelDrawingPresetColor PresetColor { get; private set; } /// /// A system color. - /// This property has a value when Type is set to System + /// This property has a value when BulletType is set to System /// public ExcelDrawingSystemColor SystemColor { get; private set; } /// @@ -181,11 +177,11 @@ public void SetRgbColor(Color color, bool setAlpha=false) RgbColor = new ExcelDrawingRgbColor(_nameSpaceManager, _colorNode) { Color = color }; } /// - /// Sets a rgb precentage color + /// Sets a rgb percentage color /// /// Red percentage /// Green percentage - /// Bluepercentage + /// Blue percentage public void SetRgbPercentageColor(double redPercentage, double greenPercentage, double bluePercentage) { ColorType = eDrawingColorType.RgbPercentage; @@ -296,6 +292,9 @@ private XmlNode GetPathNode() } return _pathNode; } - + internal Color GetColor() + { + return OfficeOpenXml.Utils.TypeConversion.ColorConverter.GetThemeColor(this); + } } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Coloring/IColorTransformItem.cs b/src/EPPlus/Drawing/Style/Coloring/IColorTransformItem.cs index b0f3be2ae6..5b7698dc97 100644 --- a/src/EPPlus/Drawing/Style/Coloring/IColorTransformItem.cs +++ b/src/EPPlus/Drawing/Style/Coloring/IColorTransformItem.cs @@ -18,7 +18,7 @@ namespace OfficeOpenXml.Drawing.Style.Coloring public interface IColorTransformItem { /// - /// Type of tranformation + /// BulletType of tranformation /// eColorTransformType Type { get; } /// diff --git a/src/EPPlus/Drawing/Style/Coloring/eColorTransformType.cs b/src/EPPlus/Drawing/Style/Coloring/eColorTransformType.cs index fae04cfaf8..75548aa3f5 100644 --- a/src/EPPlus/Drawing/Style/Coloring/eColorTransformType.cs +++ b/src/EPPlus/Drawing/Style/Coloring/eColorTransformType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing.Style.Coloring { /// - /// Type of color transformation. + /// BulletType of color transformation. /// See OOXML documentation section 20.1.2.3 for more detailed information. /// public enum eColorTransformType diff --git a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingBlipFill.cs b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingBlipFill.cs index b9a966b820..84080eb829 100644 --- a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingBlipFill.cs +++ b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingBlipFill.cs @@ -101,6 +101,7 @@ internal override void GetXml() var img = PictureStore.GetPicture(relId, this, out string contentType, out ePictureType pictureType); Image.Type = pictureType; Image.ImageBytes = img; + Image.Bounds = PictureStore.GetImageBounds(img, pictureType, _pictureRelationDocument.Package); ContentType = contentType; } SourceRectangle = new ExcelDrawingRectangle(_xml, "a:srcRect/", 0); diff --git a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingFillBase.cs b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingFillBase.cs index d5b4b79e9c..8fdda55888 100644 --- a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingFillBase.cs +++ b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingFillBase.cs @@ -42,7 +42,7 @@ internal protected ExcelDrawingFillBase(XmlNamespaceManager nsm, XmlNode topNode } /// - /// Type of fill + /// BulletType of fill /// public abstract eFillStyle Style { get; } /// diff --git a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingGradientFill.cs b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingGradientFill.cs index 3bd97ae81b..bd9f60b482 100644 --- a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingGradientFill.cs +++ b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingGradientFill.cs @@ -104,6 +104,14 @@ internal override void SetXml(XmlNamespaceManager nsm, XmlNode node) _xml.SetXmlNodePercentage("a:path/a:fillToRect/@t", FocusPoint.TopOffset, true, int.MaxValue / 10000); _xml.SetXmlNodePercentage("a:path/a:fillToRect/@l", FocusPoint.LeftOffset, true, int.MaxValue / 10000); _xml.SetXmlNodePercentage("a:path/a:fillToRect/@r", FocusPoint.RightOffset, true, int.MaxValue / 10000); + + if (TileRectangle != null) + { + _xml.SetXmlNodePercentage("a:path/a:tileRect/@b", TileRectangle.BottomOffset, true, int.MaxValue / 10000); + _xml.SetXmlNodePercentage("a:path/a:tileRect/@t", TileRectangle.TopOffset, true, int.MaxValue / 10000); + _xml.SetXmlNodePercentage("a:path/a:tileRect/@l", TileRectangle.LeftOffset, true, int.MaxValue / 10000); + _xml.SetXmlNodePercentage("a:path/a:tileRect/@r", TileRectangle.RightOffset, true, int.MaxValue / 10000); + } } } @@ -148,8 +156,11 @@ internal override void GetXml() { foreach (XmlNode c in cols.ChildNodes) { - var xml = XmlHelperFactory.Create(_xml.NameSpaceManager, c); - _colors.Add(xml.GetXmlNodeDouble("@pos") / 1000, c); + if (c.NodeType == XmlNodeType.Element) + { + var xml = XmlHelperFactory.Create(_xml.NameSpaceManager, c); + _colors.Add(xml.GetXmlNodeDouble("@pos") / 1000, c); + } } } var path=_xml.GetXmlNodeString("a:path/@path"); @@ -169,6 +180,7 @@ internal override void GetXml() else { FocusPoint = new ExcelDrawingRectangle(_xml, "a:path/a:fillToRect/", 0); + TileRectangle = new ExcelDrawingRectangle(_xml, "a:tileRect/", 0); } } eShadePath _shadePath = eShadePath.Linear; @@ -207,6 +219,15 @@ public ExcelDrawingRectangle FocusPoint private set; } /// + /// The tile rectangle when ShadePath is set to a non linear value. + /// This property is set to null if ShadePath is set to Linear + /// + public ExcelDrawingRectangle TileRectangle + { + get; + private set; + } + /// /// Linear gradient settings. /// This property is set to null if ShadePath is set to Linear /// @@ -219,7 +240,6 @@ internal override void UpdateXml() { if (_xml == null) CreateXmlHelper(); SetXml(_nsm, _xml.TopNode); - } } } diff --git a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingPatternFill.cs b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingPatternFill.cs index 157b9ceff2..f7eb753fec 100644 --- a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingPatternFill.cs +++ b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingPatternFill.cs @@ -112,10 +112,7 @@ internal override void SetXml(XmlNamespaceManager nsm, XmlNode node) } _xml.SetXmlNodeString("@prst", PatternType.ToEnumString()); var fgNode=_xml.CreateNode("a:fgClr"); - ForegroundColor.SetXml(nsm, fgNode); - var bgNode = _xml.CreateNode("a:bgClr"); - BackgroundColor.SetXml(nsm, bgNode); } internal override void GetXml() { diff --git a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingSolidFill.cs b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingSolidFill.cs index 169e40fe5e..e864711d2a 100644 --- a/src/EPPlus/Drawing/Style/Fill/ExcelDrawingSolidFill.cs +++ b/src/EPPlus/Drawing/Style/Fill/ExcelDrawingSolidFill.cs @@ -85,7 +85,6 @@ internal override void SetXml(XmlNamespaceManager nsm, XmlNode node) { Color.SetPresetColor(ePresetColor.Black); } - _color.SetXml(nsm, node); } internal override void GetXml() { diff --git a/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontBase.cs b/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontBase.cs index 208b08875d..00d92c66ab 100644 --- a/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontBase.cs +++ b/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontBase.cs @@ -11,6 +11,8 @@ Date Author Change 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ using OfficeOpenXml.Drawing.Style; +using OfficeOpenXml.Utils.String; +using System; using System.Xml; namespace OfficeOpenXml.Drawing.Style.Font @@ -20,9 +22,12 @@ namespace OfficeOpenXml.Drawing.Style.Font /// public class ExcelDrawingFontBase : XmlHelper { - internal ExcelDrawingFontBase(XmlNamespaceManager nameSpaceManager, XmlNode topNode) : base(nameSpaceManager, topNode) + internal Action _initXml = null; + internal string _path; + internal ExcelDrawingFontBase(XmlNamespaceManager nameSpaceManager, XmlNode topNode, string path = "", Action initXml = null) : base(nameSpaceManager, topNode) { - + _path = path.AddTrailingSlash(); + _initXml = initXml; } /// /// The typeface or the name of the font @@ -31,11 +36,11 @@ public string Typeface { get { - return GetXmlNodeString("@typeface"); + return GetXmlNodeString($"{_path}@typeface"); } internal set { - SetXmlNodeString("@typeface", value); + SetXmlNodeString($"{_path}@typeface", value); } } } diff --git a/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontSpecial.cs b/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontSpecial.cs index 6930ca7fe0..a0d46e6d44 100644 --- a/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontSpecial.cs +++ b/src/EPPlus/Drawing/Style/Font/ExcelDrawingFontSpecial.cs @@ -11,6 +11,9 @@ Date Author Change 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ using OfficeOpenXml.Drawing.Style; +using OfficeOpenXml.Utils.String; +using System; +using System.IO; using System.Xml; namespace OfficeOpenXml.Drawing.Style.Font @@ -20,9 +23,8 @@ namespace OfficeOpenXml.Drawing.Style.Font /// public class ExcelDrawingFontSpecial : ExcelDrawingFontBase { - internal ExcelDrawingFontSpecial(XmlNamespaceManager nameSpaceManager, XmlNode topNode) : base(nameSpaceManager, topNode) + internal ExcelDrawingFontSpecial(XmlNamespaceManager nameSpaceManager, XmlNode topNode, string path="", Action initXml=null) : base(nameSpaceManager, topNode, path, initXml) { - } /// /// The type of font @@ -53,11 +55,12 @@ public string Panose { get { - return GetXmlNodeString("@panose"); + return GetXmlNodeString($"{_path}@panose"); } set { - SetXmlNodeString("@panose",value); + _initXml?.Invoke(); + SetXmlNodeString($"{_path}@panose",value); } } /// @@ -67,7 +70,7 @@ public ePitchFamily PitchFamily { get { - var p=GetXmlNodeInt("@pitchFamily"); + var p=GetXmlNodeInt($"{_path}@pitchFamily"); try { return (ePitchFamily)p; @@ -79,9 +82,25 @@ public ePitchFamily PitchFamily } set { - SetXmlNodeString("@pitchFamily", ((int)value).ToString()); + _initXml?.Invoke(); + SetXmlNodeString($"{_path}@pitchFamily", ((int)value).ToString()); + } + } + /// + /// The character set which is supported by the parent font. + /// See OOXML documentation for details. + /// + public int Charset + { + get + { + return GetXmlNodeInt($"{_path}@charset", 1); + } + set + { + _initXml?.Invoke(); + SetXmlNodeInt($"{_path}@charset", value); } } - } } \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/Bullet/ExcelDrawingBulletSize.cs b/src/EPPlus/Drawing/Style/Text/Bullet/ExcelDrawingBulletSize.cs new file mode 100644 index 0000000000..233b5a60a3 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/Bullet/ExcelDrawingBulletSize.cs @@ -0,0 +1,132 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; +using System.Globalization; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + public class ExcelDrawingBulletSize : XmlHelper + { + const string BuSzPct = "/a:buSzPct"; + const string BuSzPts = "/a:buSzPts"; + const string BuSzTx = "/a:buSzTx"; + string _path; + XmlNode _currentNode=null; + internal ExcelDrawingBulletSize(XmlNamespaceManager nsm, XmlNode topNode, string path, string[] schemaNodeOrder, Action initXml) : base(nsm, topNode) + { + SchemaNodeOrder = schemaNodeOrder; + _path = path; + var node = GetNode(path); + if(node!=null) + { + _currentNode = GetNode(path + BuSzPct); + if (_currentNode == null) + { + _currentNode = GetNode(path + BuSzPts); + if (_currentNode == null) + { + Type = eBulletSizeType.FollowText; + } + else + { + Type = eBulletSizeType.Points; + } + } + else + { + Type = eBulletSizeType.PercentOfText; + } + } + else + { + Type = eBulletSizeType.PercentOfText; + } + } + public eBulletSizeType Type + { + get; + } + /// + /// The value if is set to PercentOfText or Points. + /// + public double? Value + { + get + { + if (Type == eBulletSizeType.PercentOfText) + { + return XmlHelper.GetRichTextPropertyDouble(_currentNode) / 1000; + } + else if(Type == eBulletSizeType.Points) + { + return XmlHelper.GetRichTextPropertyDouble(_currentNode) / 100; + } + return null; + } + internal set + { + if (value.HasValue == false) + { + _currentNode.Attributes.Remove(_currentNode.Attributes["val"]); + } + if(Type == eBulletSizeType.PercentOfText) + { + SetXmlNodeString(_currentNode, "/@val", (value.Value * 1000).ToString(CultureInfo.InvariantCulture)); + } + else if (Type == eBulletSizeType.Points) + { + SetXmlNodeString(_currentNode, "/@val", (value.Value * 100).ToString(CultureInfo.InvariantCulture)); + } + else + { + throw new InvalidOperationException("Bullets with type eBulletSizeType.FollowText cannot have a Value"); + } + } + } + /// + /// Sets the bullet size to follow the text. + /// + public void SetFollowText() + { + if (Type == eBulletSizeType.FollowText) return; + DeleteNode(_path + BuSzPts); + DeleteNode(_path + BuSzPct); + CreateNode(_path + BuSzTx); + } + /// + /// Sets the bullet to a percentage of the text within the paragraph. + /// + /// The value in percent, where 100% is 100 + public void SetPercent(double value) + { + DeleteNode(_path + BuSzPts); + DeleteNode(_path + BuSzTx); + CreateNode(_path + BuSzPct); + + Value = value * 100; + } + /// + /// Sets the bullet to a size in points. + /// + /// Value in points + public void SetPoint(double value) + { + DeleteNode(_path + BuSzPct); + DeleteNode(_path + BuSzTx); + CreateNode(_path + BuSzPts); + + Value = value * 1000; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/Bullet/ExcelParagraphBullet.cs b/src/EPPlus/Drawing/Style/Text/Bullet/ExcelParagraphBullet.cs new file mode 100644 index 0000000000..903e2fbd12 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/Bullet/ExcelParagraphBullet.cs @@ -0,0 +1,197 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.CellPictures; +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Coloring; +using OfficeOpenXml.Drawing.Style.Font; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Packaging; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.IO; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + public class ExcelParagraphBullet : XmlHelper, IPictureContainer + { + string _path; + Action _initXml; + IPictureRelationDocument _prd; + internal ExcelParagraphBullet(IPictureRelationDocument pictureRelationDocument, XmlNamespaceManager nsm, XmlNode topNode, string path, string[] schemaNodeOrder, Action initXml) : base(nsm, topNode) + { + _prd = pictureRelationDocument; + _initXml = initXml; + _path = path; + Color = new ExcelDrawingColorManager(nsm, topNode, path + "/a:buClr", SchemaNodeOrder, initXml); + Font = new ExcelDrawingFontSpecial(nsm, topNode, path + "/a:buFont", initXml); + Size = new ExcelDrawingBulletSize(nsm, topNode, path, SchemaNodeOrder, initXml); + AutoNumberType = GetXmlEnumNull(path + "/a:buAutoNum/@type"); + if(AutoNumberType.HasValue) + { + BulletType = eBulletType.AutoNum; + StartAt = GetXmlNodeInt(path + "/a:buAutoNum/@startAt", 1); + } + else + { + if(ExistsNode(path + "/a:buNone")) + { + BulletType = eBulletType.None; + } + else + { + string buChar = GetXmlNodeString(path + "/a:buChar/@char"); + if(string.IsNullOrEmpty(buChar)) + { + RelId = GetXmlNodeString(path + "/a:buBlip/@r:embed"); + if(string.IsNullOrEmpty(RelId)==false) + { + BulletType = eBulletType.Blip; + var imageBytes = PictureStore.GetPicture(RelId, this, out string contentType, out ePictureType pt); + BulletImage = new ExcelImage(imageBytes, pt); + //TODO: Add + } + else + { + BulletType = eBulletType.None; + } + } + else + { + BulletType = eBulletType.Character; + BulletCharacter = buChar[0]; + } + } + } + } + /// + /// The type of bullet. + /// + public eBulletType BulletType + { + get; + private set; + } + /// + /// The color of the bullet character. + /// + public ExcelDrawingColorManager Color { get; } + /// + /// The font used for the bullet character. + /// + public ExcelDrawingFontSpecial Font { get; } + /// + /// The size used for the bullet. + /// + public ExcelDrawingBulletSize Size { get; } + /// + /// The bullet character, if bullet type is set to Character. + /// + public char? BulletCharacter { get; private set; } + /// + /// The start value if the bullet type is set to AutoNumber. Default is 1. + /// + public int StartAt { get; private set; } + /// + /// The type of auto numbering, if bullet type is set to AutoNumber. + /// + public eBulletAutoNumberType? AutoNumberType + { + get; + private set; + } + ExcelImage _image=null; + /// + /// The BulletImage + /// + public ExcelImage BulletImage + { + get + { + if (BulletType != eBulletType.Blip) return null; + return _image; + } + private set + { + _image = value; + } + } + private string RelId { get; set; } + IPictureRelationDocument IPictureContainer.RelationDocument => _prd; + + string IPictureContainer.ImageHash { get; set; } + Uri IPictureContainer.UriPic { get; set; } + ZipPackageRelationship IPictureContainer.RelPic { get; set; } + /// + /// Sets the Bullet Type to None + /// + public void SetNone() + { + BulletType = eBulletType.None; + AutoNumberType = null; + BulletCharacter = null; + CreateNode(_path + "/a:buNone"); + DeleteNode(_path + "/a:buChar"); + DeleteNode(_path + "/a:buAutoNum"); + DeleteNode(_path + "/a:buBlip"); + } + public void SetAutoNumber(eBulletAutoNumberType type, int startAt = 1) + { + AutoNumberType = type; + StartAt = startAt; + SetXmlNodeString(_path + "/a:buAutoNum/@type", type.ToEnumString()); + if (startAt > 1) + { + SetXmlNodeInt(_path + "/a:buAutoNum/@startAt", startAt); + } + DeleteNode(_path + "/a:buNone"); + DeleteNode(_path + "/a:buChar"); + DeleteNode(_path + "/a:buBlip"); + BulletType = eBulletType.AutoNum; + } + public void SetCharacter(char bulletCharacter) + { + DeleteNode(_path + "/a:buNone"); + DeleteNode(_path + "/a:buAutoNum"); + DeleteNode(_path + "/a:buBlip"); + + SetXmlNodeString(_path + "/a:buChar", bulletCharacter.ToString()); + BulletType = eBulletType.Character; + } + public void SetPicture(Stream image) + { + CreateNode(_path + "/a:buNone"); + DeleteNode(_path + "/a:buChar"); + DeleteNode(_path + "/a:buAutoNum"); + DeleteNode(_path + "/a:buBlip"); + if (BulletType==eBulletType.Blip) + { + PictureStore.RemoveImage(this); + } + BulletImage = new ExcelImage(image); + ((IPictureContainer)this).SetNewImage(); + BulletType = eBulletType.Blip; + } + + void IPictureContainer.RemoveImage() + { + PictureStore.RemoveImage(this); + } + + void IPictureContainer.SetNewImage() + { + SetXmlNodeString(_path + "/a:buBlip/@r:embed", ((IPictureContainer)this).RelPic.Id); + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/Bullet/eBulletAutoNumberType.cs b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletAutoNumberType.cs new file mode 100644 index 0000000000..b43afb312a --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletAutoNumberType.cs @@ -0,0 +1,59 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + public enum eBulletAutoNumberType + { + AlphaLcParenBoth, + AlphaUcParenBoth, + AlphaLcParenR, + AlphaUcParenR, + AlphaLcPeriod, + AlphaUcPeriod, + ArabicParenBoth, + ArabicParenR, + ArabicPeriod, + ArabicPlain, + RomanLcParenBoth, + RomanUcParenBoth, + RomanLcParenR, + RomanUcParenR, + RomanLcPeriod, + RomanUcPeriod, + CircleNumDbPlain, + CircleNumWdBlackPlain, + CircleNumWdWhitePlain, + ArabicDbPeriod, + ArabicDbPlain, + Ea1ChsPeriod, + Ea1ChsPlain, + Ea1ChtPeriod, + Ea1ChtPlain, + Ea1JpnChsDbPeriod, + Ea1JpnKorPlain, + Ea1JpnKorPeriod, + Arabic1Minus, + Arabic2Minus, + Hebrew2Minus, + ThaiAlphaPeriod, + ThaiAlphaParenR, + ThaiAlphaParenBoth, + ThaiNumPeriod, + ThaiNumParenR, + ThaiNumParenBoth, + HindiAlphaPeriod, + HindiNumPeriod, + HindiNumParenR, + HindiAlpha1Period + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/Bullet/eBulletSizeType.cs b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletSizeType.cs new file mode 100644 index 0000000000..f76f19d226 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletSizeType.cs @@ -0,0 +1,30 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + public enum eBulletSizeType + { + /// + /// The size of the bullet characters is in percentage of the surrounding text within the paragraph + /// + PercentOfText, + /// + /// The size of the bullet characters is points + /// + Points, + /// + /// The size of the bullet characters is the same points as the surrounding text. + /// + FollowText + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/Bullet/eBulletType.cs b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletType.cs new file mode 100644 index 0000000000..ee471ad8e3 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/Bullet/eBulletType.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + /// + /// The type of bullet in a paragraph in a drawings text. + /// + public enum eBulletType + { + /// + /// No bullet + /// + None, + /// + /// Auto numbering + /// + AutoNum, + /// + /// Use a character for the bullet. + /// + Character, + /// + /// Use a picture for the bullet. + /// + Blip + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraph.cs b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraph.cs new file mode 100644 index 0000000000..a29a112819 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraph.cs @@ -0,0 +1,423 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Core; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Text; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + /// + /// Represents a paragraph in a richtext within a drawing object. + /// + public class ExcelDrawingParagraph : XmlHelper + { + Action _initXml; + internal IPictureRelationDocument _prd; + internal ExcelDrawingParagraphCollection _paragraphs; + + //bool legacyDefaultRunPropertySetting = false; + + internal ExcelDrawingParagraph(ExcelDrawingParagraphCollection paragraphs, IPictureRelationDocument prd, XmlNamespaceManager nameSpaceManager, XmlNode topNode, string[] schemaNodeOrder, Action initXml) : base(nameSpaceManager, topNode) + { + _paragraphs = paragraphs; + AddSchemaNodeOrder(schemaNodeOrder, ["lnSpc", "spcBef", "spcAft", "buClrTx", "buClr", "buSzPct", "buSzTx", "buSzPts", "buFont", "buFontTx", "buAutoNum", "buChar", "buBlip", "buNone", "tabLst", "defRPr"]); + _initXml = initXml; + _prd = prd; + + + + if (_paragraphs.FirstDefaultRunProperties == null) + { + DefaultRunProperties = new ExcelTextFontXml(prd, nameSpaceManager, topNode, "a:pPr/a:defRPr", schemaNodeOrder, initXml); + } + else + { + DefaultRunProperties = _paragraphs.FirstDefaultRunProperties; + //if(paragraphs.Count == 0) + //{ + // //The node must still be created + // var xmlFirstDefault = ((ExcelTextFontXml)paragraphs.FirstDefaultRunProperties).XmlHelper.TopNode.ParentNode; + // XmlNode paragraphProperties = topNode.SelectSingleNode("a:pPr", NameSpaceManager); + + // //Create paragraph properties if it does not already exist + // if (paragraphProperties == null) + // { + // paragraphProperties = CreateNode(topNode, "a:pPr", true); + // } + // //Create defRPr + // var textFont = new ExcelTextFontXml(prd, nameSpaceManager, topNode, "a:pPr/a:defRPr", schemaNodeOrder, initXml); + + // //Copy the first element and apply it to the paragraphProperties + // CopyElement((XmlElement)xmlFirstDefault, (XmlElement)paragraphProperties); + // DefaultRunProperties = textFont; + //} + //else + //{ + // DefaultRunProperties = _paragraphs.FirstDefaultRunProperties; + //} + } + + var normalStyle = _prd.Package.Workbook.Styles.GetNormalStyle(); + + //////Previously new paragraphs used the first DefaultRunProperties + //////Uncertain if we should keep this behaviour at least as an option. TODO: Decide if breaking change or legacy setting (or keep only previous paragraph's settings?) + bool legacyDefaultRunPropertySetting = false; + + if (paragraphs.Count == 0) + { + if (_paragraphs.FirstDefaultRunProperties == null) + { + if (normalStyle == null) + { + DefaultRunProperties.LatinFont = DefaultRunProperties.ComplexFont = "Calibri"; + } + else + { + if (string.IsNullOrEmpty(DefaultRunProperties.LatinFont)) + { + DefaultRunProperties.LatinFont = normalStyle.Style.Font.Name; + } + + if (string.IsNullOrEmpty(DefaultRunProperties.ComplexFont)) + { + DefaultRunProperties.ComplexFont = normalStyle.Style.Font.Name; + } + } + } + else + { + //if(topNode.ParentNode != _paragraphs.FirstDefaultRunProperties) + ////The node must still be created + //var xmlFirstDefault = ((ExcelTextFontXml)paragraphs.FirstDefaultRunProperties).XmlHelper.TopNode.ParentNode; + //XmlNode paragraphProperties = topNode.SelectSingleNode("a:pPr", NameSpaceManager); + + ////Create paragraph properties if it does not already exist + //if (paragraphProperties == null) + //{ + // paragraphProperties = CreateNode(topNode, "a:pPr", true); + //} + ////Create defRPr + //var textFont = new ExcelTextFontXml(prd, nameSpaceManager, topNode, "a:pPr/a:defRPr", schemaNodeOrder, initXml); + + ////Copy the first element and apply it to the paragraphProperties + //CopyElement((XmlElement)xmlFirstDefault, (XmlElement)paragraphProperties); + //DefaultRunProperties = textFont; + } + } + else if (legacyDefaultRunPropertySetting && _paragraphs.FirstDefaultRunProperties != null) + { + ((ExcelTextFontXml)DefaultRunProperties).TriggerCreateTopNodeOnTextSet(); + + var xmlFirstDefault = ((ExcelTextFontXml)paragraphs.FirstDefaultRunProperties).XmlHelper; + var xmlNewNode = ((ExcelTextFontXml)DefaultRunProperties).XmlHelper; + CopyElement((XmlElement)xmlFirstDefault.TopNode, (XmlElement)xmlNewNode.TopNode); + } + } + /// + /// Default font and fill properties for all text runs. + /// + public ExcelTextFont DefaultRunProperties + { + get; + } + + ExcelDrawingTextRunCollection _textRun = null; + /// + /// A collection of text runs for the paragraph + /// + public ExcelDrawingTextRunCollection TextRuns + { + get + { + if (_textRun == null) + { + _textRun = new ExcelDrawingTextRunCollection(this, NameSpaceManager, TopNode, _initXml); + } + return _textRun; + } + } + /// + /// The text for the paragraph. + /// + public string Text + { + get + { + var sb = new StringBuilder(); + foreach (var tr in TextRuns) + { + sb.Append(tr.Text); + } + return sb.ToString(); + } + } + + + internal eTextAlignment defaultAlignment = eTextAlignment.Left; + /// + /// Horizontal Alignment + /// + public eTextAlignment HorizontalAlignment + { + get + { + return GetXmlNodeString("a:pPr/@algn").ToEnum(defaultAlignment, new Dictionary + { + ["r"] = eTextAlignment.Right, + ["ctr"] = eTextAlignment.Center, + ["dist"] = eTextAlignment.Distributed, + ["just"] = eTextAlignment.Justified, + ["justLow"] = eTextAlignment.JustifiedLow, + ["thaiDist"] = eTextAlignment.ThaiDistributed, + ["l"] = eTextAlignment.Left, + } + ); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString("a:pPr/@algn", value.ToEnumString(new Dictionary + { + [eTextAlignment.Right] = "r", + [eTextAlignment.Center] = "ctr", + [eTextAlignment.Distributed] = "dist", + [eTextAlignment.Justified] = "just", + [eTextAlignment.JustifiedLow] = "justLow", + [eTextAlignment.ThaiDistributed] = "thaiDist", + [eTextAlignment.Left] = "l", + })); + } + } + /// + /// Default width in pixels for a TAB character. + /// + //If omitted default in office is 914400 EMUs + public double? DefaultTabSize + { + get + { + return GetXmlNodeEmuToPixelNull("a:pPr/@defTabSz"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPixel("a:pPr/@defTabSz", value); + } + } + /// + /// Left margin in pixels. This is specified in addition to the text body inset and applies only to this text paragraph + /// + public double LeftMargin + { + get + { + return GetXmlNodeEmuToPixel("a:pPr/@marL"/*,347663 / ExcelDrawing.EMU_PER_PIXEL*/); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPixel("a:pPr/@marL", value); + } + } + /// + /// Right margin in pixels. This is specified in addition to the text body inset and applies only to this text paragraph + /// + public double RightMargin + { + get + { + return GetXmlNodeEmuToPixel("a:pPr/@marR"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPixel("a:pPr/@marR", value); + } + } + /// + /// The indent size that is applied to the first line of text in the paragraph in pixels. + /// 0 means indent is same as MarL attribute. If this node would be null then it is considered -342900 (to counter the default value of MarL) + /// + public double Indent + { + get + { + var indent = GetXmlNodeEmuToPixel("a:pPr/@indent"); + //if (indent == 0) + //{ + // return GetXmlNodeEmuToPixel("a:pPr/@marL", -342900 / ExcelDrawing.EMU_PER_PIXEL); + //} + return indent; + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPixel("a:pPr/@indent", value); + } + } + /// + /// Right-to-left flow direction. + /// + public bool RightToLeft + { + get + { + return GetXmlNodeBool("a:pPr/@rtl"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool("a:pPr/@rtl", value, false); + } + } + /// + /// The level of the paragraph in relation to the list style. + /// + public int IndentLevel + { + get + { + return GetXmlNodeInt("a:pPr/@lvl", 0); + } + set + { + //From the docs: + //"-1 and -2 for outline mode levels that should only exist in memory" + //ECMA december_2016 part1 page 20.1.10.71 ST_TextIndentLevelType (Text Indent Level Type) + if (value < -2 && value > 8) + { + throw new ArgumentOutOfRangeException("Level must be between 0 and 8"); + } + _initXml?.Invoke(); + SetXmlNodeInt("a:pPr/@lvl", value); + } + } + /// + /// If a Latin word can be broken in half and wrapped onto the next line without a hyphen being added. + /// + public bool LatinLineBreak + { + get + { + return GetXmlNodeBool("a:pPr/@latinLnBrk"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool("a:pPr/@latinLnBrk", value, false); + } + } + /// + /// If an East Asian word can be broken in half and wrapped onto the next line without a hyphen being added. + /// + public bool EastAsianLineBreak + { + get + { + return GetXmlNodeBool("a:pPr/@eaLnBrk"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool("a:pPr/@eaLnBrk", value, false); + } + } + /// + /// If a punctuation is to be forcefully laid out on a line of text or put on a different line of text. + /// + public bool HangingPunctuation + { + get + { + return GetXmlNodeBool("a:pPr/@hangingPunct"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool("a:pPr/@hangingPunct", value, false); + } + } + ExcelLineSpacing _spaceBefore = null; + public ExcelLineSpacing SpaceBefore + { + get + { + if (_spaceBefore == null) + { + _spaceBefore = new ExcelLineSpacing(NameSpaceManager, TopNode, "a:pPr/a:spcBef", SchemaNodeOrder, _initXml, eDrawingTextLineSpacing.Exactly); + } + return _spaceBefore; + } + } + ExcelLineSpacing _spaceAfter = null; + public ExcelLineSpacing SpaceAfter + { + get + { + if (_spaceAfter == null) + { + _spaceAfter = new ExcelLineSpacing(NameSpaceManager, TopNode, "a:pPr/a:spcAft", SchemaNodeOrder, _initXml, eDrawingTextLineSpacing.Exactly); + } + return _spaceAfter; + } + } + ExcelLineSpacing _lineSpacing = null; + public ExcelLineSpacing LineSpacing + { + get + { + if (_lineSpacing == null) + { + _lineSpacing = new ExcelLineSpacing(NameSpaceManager, TopNode, "a:pPr/a:lnSpc", SchemaNodeOrder, _initXml, eDrawingTextLineSpacing.Single); + } + return _lineSpacing; + } + } + ExcelParagraphBullet _bullet = null; + public ExcelParagraphBullet Bullet + { + get + { + if (_bullet == null) + { + _bullet = new ExcelParagraphBullet(_prd, NameSpaceManager, TopNode, "a:pPr", SchemaNodeOrder, _initXml); + } + return _bullet; + } + } + ExcelDrawingParagraphTabStopCollection _tabStops = null; + public ExcelDrawingParagraphTabStopCollection TabStops + { + get + { + if (_tabStops == null) + { + _tabStops = new ExcelDrawingParagraphTabStopCollection(NameSpaceManager, TopNode, SchemaNodeOrder, _initXml); + } + return _tabStops; + } + } + } +} diff --git a/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphCollection.cs b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphCollection.cs new file mode 100644 index 0000000000..09241b4506 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphCollection.cs @@ -0,0 +1,290 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + public class ExcelDrawingParagraphCollection : XmlHelper, IEnumerable + { + IPictureRelationDocument _prd; + string _path; + Action _initXml = null; + List _paragraphs = new List(); + internal Action _addCallback = null; + internal Action _removeParagraphCallback = null; + internal Action _removeTextRunCallback = null; + internal ExcelTextBody _tb; + internal ExcelDrawingParagraphCollection(IPictureRelationDocument prd, XmlNamespaceManager nsm, XmlNode topNode, string path, string[] schemaNodeOrder, Action initXml) : base(nsm, topNode) + { + _prd = prd; + var rootNode = GetNode(path); + _path = path; + if (rootNode != null) + { + TopNode = rootNode; + var pNodes = GetNodes("a:p"); + pNodes = pNodes.Count == 0 ? GetNodes("../a:p") : pNodes; + foreach (XmlElement pn in pNodes) + { + var paragraph = new ExcelDrawingParagraph(this, prd, NameSpaceManager, pn, schemaNodeOrder, initXml); + _paragraphs.Add(paragraph); + //if (_paragraphs.Count == 1 && FirstDefaultRunProperties == null) + //{ + // FirstDefaultRunProperties = paragraph.DefaultRunProperties; + //} + } + + if (_paragraphs.Count == 0) + { + CreateParagraphPlaceHolder(); + } + } + AddSchemaNodeOrder(schemaNodeOrder, ["rPr", "pPr", "t"]); + } + + public int Count { get => _paragraphs.Count; } + + public ExcelDrawingParagraph this[int index] + { + get + { + return _paragraphs[index]; + } + + } + /// + /// Adds a new paragraph + /// + /// + /// + public ExcelDrawingParagraph Add(string text) + { + XmlNode pn = PlaceHolderNode; + if (_paragraphs.Count == 0 && pn == null) + { + CreateTopNode(); + } + + if (pn == null) + { + pn = CreateNode("a:p", false, true); + } + + var p = new ExcelDrawingParagraph(this, _prd, NameSpaceManager, pn, SchemaNodeOrder, _initXml); + + var tr = p.TextRuns.Add(text); + + _paragraphs.Add(p); + //_addCallback?.Invoke(tr); + + if (PlaceHolderNode != null) + { + PlaceHolderNode = null; + } + return p; + } + /// + /// Default run properties for the entire shape + /// + internal ExcelTextFont FirstDefaultRunProperties = null; + + internal ExcelTextFont CreateOrGetDefaultRunProperties(string fontPath, XmlNode rootNode) + { + if(_paragraphs.Count != 0) + { + if(FirstDefaultRunProperties == null) + { + FirstDefaultRunProperties = _paragraphs[0].DefaultRunProperties; + } + + return _paragraphs[0].DefaultRunProperties; + } + + FirstDefaultRunProperties = new ExcelTextFontXml(_prd, NameSpaceManager, rootNode, fontPath, SchemaNodeOrder, _initXml); + ((ExcelTextFontXml)FirstDefaultRunProperties).TriggerCreateTopNodeOnTextSet(); + return FirstDefaultRunProperties; + } + + XmlNode PlaceHolderNode = null; + + internal void CreateParagraphPlaceHolder() + { + if(PlaceHolderNode == null && _paragraphs.Count == 0) + { + var pn = CreateNode("a:p", false, true); + PlaceHolderNode = pn; + } + } + + internal XmlNode CreateAndReturnParagraphPlaceHolder() + { + if(PlaceHolderNode == null) + { + CreateParagraphPlaceHolder(); + } + return PlaceHolderNode; + } + + internal void SetPlaceHolderNode(XmlNode node) + { + PlaceHolderNode = node; + } + + + /// + /// Removes the item at the index from the collection + /// + /// The index + /// + public void RemoveAt(int index) + { + if (index < 0 || index >= _paragraphs.Count) + { + throw new IndexOutOfRangeException("Paragraph index out of range."); + } + var pn = _paragraphs[index].TopNode; + pn.ParentNode.RemoveChild(pn); + _paragraphs.RemoveAt(index); + _removeParagraphCallback?.Invoke(_paragraphs[index]); + } + /// + /// Removes the item from the collection + /// + /// The item to remove + /// + public void Remove(ExcelDrawingParagraph item) + { + if (!_paragraphs.Contains(item)) + { + throw new ArgumentException("Paragraph item does not exist in the collection"); + } + var pn = item.TopNode; + pn.ParentNode.RemoveChild(pn); + _paragraphs.Remove(item); + _removeParagraphCallback?.Invoke(item); + } + /// + /// Gets the enumerator. + /// + /// + public IEnumerator GetEnumerator() + { + return _paragraphs.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int IndexOf(ExcelDrawingParagraph item) + { + return _paragraphs.IndexOf(item); + } + /// + /// Clear all paragraphs from the collection + /// + public void Clear() + { + for (int i = 0; i < _paragraphs.Count; i++) + { + var pn= _paragraphs[i].TopNode; + pn.ParentNode.RemoveChild(pn); + _removeParagraphCallback?.Invoke(_paragraphs[0]); + } + _paragraphs.Clear(); + } + /// + /// The text + /// + public string Text + { + get + { + if(Count==0) return ""; + StringBuilder sb = new StringBuilder(); + + foreach(var p in _paragraphs) + { + foreach(var tr in p.TextRuns) + { + sb.Append(tr.Text); + } + sb.Append(Environment.NewLine); + } + + return sb.ToString().Substring(0, sb.Length - Environment.NewLine.Length); + } + } + /// + /// Returns true if the paragraph exists in the collection. + /// + /// The paragraph to check for + /// True if exists + public bool Contains(ExcelDrawingParagraph item) + { + return _paragraphs.Contains(item); + } + /// + /// Creates the top nodes of the collection + /// + protected internal void CreateTopNode() + { + if (_paragraphs.Count == 0 && PlaceHolderNode == null) + { + if(GetNode(_path) == null) + { + _initXml?.Invoke(); + TopNode = CreateNode(_path); + CreateNode("a:bodyPr"); + CreateNode("a:lstStyle"); + } + } + } + + /// + /// How text is wrapped according to Parent Node + /// KEEP INTERNAL. Or remove and give some other reference to the parent node's text-wrapping node. + /// + internal eTextWrappingType WrapText + { + get + { + //Note: Gets the wrap attribute which is controlled by TextBody + return GetXmlNodeString($"a:bodyPr/@wrap").ToEnum(eTextWrappingType.Square); + } + //set + //{ + // _initXml?.Invoke(); + // //Note: Gets the wrap attribute of the PARENT node + // SetXmlNodeString($"{_path}/bodyPr/@wrap", value.ToEnumString()); + //} + } + + internal void SetUpdateCallbacks(Action addCallback, Action removeParagraphCallback, Action removeTextRunCallback) + { + _addCallback = addCallback; + _removeParagraphCallback = removeParagraphCallback; + _removeTextRunCallback = removeTextRunCallback; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphTabStopCollection.cs b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphTabStopCollection.cs new file mode 100644 index 0000000000..b9cf226ab6 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelDrawingParagraphTabStopCollection.cs @@ -0,0 +1,57 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +using OfficeOpenXml.Drawing.Interfaces; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + public class ExcelDrawingParagraphTabStopCollection : XmlHelper, IEnumerable + { + List _tabStops = new List(); + internal ExcelDrawingParagraphTabStopCollection(XmlNamespaceManager nameSpaceManager, XmlNode topNode, string[] schemaNodeOrder, Action initXml) : base(nameSpaceManager, topNode) + { + var pNodes = topNode.SelectNodes("a:pPr/a:tabLst/a:tab", nameSpaceManager); + + foreach(XmlElement pn in pNodes) + { + _tabStops.Add(new ExcelDrawingParagraphTabStop(nameSpaceManager, pn, schemaNodeOrder, initXml)); + } + } + public int Count { get => _tabStops.Count; } + public ExcelDrawingParagraphTabStop this[int PositionID] + { + get + { + return _tabStops[PositionID]; + } + } + /// + /// Gets the enumerator. + /// + /// + public IEnumerator GetEnumerator() + { + return _tabStops.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/ExcelDrawingTextRunCollection.cs b/src/EPPlus/Drawing/Style/Text/ExcelDrawingTextRunCollection.cs new file mode 100644 index 0000000000..aa01293b43 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelDrawingTextRunCollection.cs @@ -0,0 +1,189 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType.Utils; +using OfficeOpenXml.Style; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Interfaces.RichText; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.DrawingRenderer.RenderItems.Textbox; + +namespace OfficeOpenXml.Drawing +{ + public class ExcelDrawingTextRunCollection : XmlHelper, IEnumerable + { + List _textRuns; + ExcelDrawingParagraph _paragraph; + Action _initXml; + internal ExcelDrawingTextRunCollection(ExcelDrawingParagraph paragraph, XmlNamespaceManager nsm, XmlNode topNode, Action initXml) : base(nsm, topNode) + { + _paragraph = paragraph; + AddSchemaNodeOrder(_paragraph.SchemaNodeOrder, ["rPr", "pPr", "t"]); + _initXml = initXml; + _textRuns = new List(); + foreach (XmlElement node in topNode.SelectNodes("a:r|a:fld|a:br", nsm)) + { + + switch (node.LocalName) + { + case "r": + _textRuns.Add(new ExcelParagraphTextRun(paragraph, nsm, node)); + break; + case "fld": + _textRuns.Add(new ExcelParagraphTextField(paragraph, nsm, node)); + break; + case "br": + _textRuns.Add(new ExcelParagraphLineBreak(paragraph, nsm, node)); + break; + } + } + } + /// + /// Number of items in the collection. + /// + public int Count { get => _textRuns.Count; } + /// + /// Return the text run at the index. + /// + /// The index + /// + public ExcelParagraphTextRunBase this[int index] + { + get + { + return _textRuns[index]; + } + } + + /// + /// Removes the item at the index from the collection + /// + /// The index + /// + public void RemoveAt(int index) + { + if (index < 0 || index >= _textRuns.Count) + { + throw new IndexOutOfRangeException("Paragraph index out of range."); + } + var pn = _textRuns[index].TopNode; + pn.ParentNode.RemoveChild(pn); + _paragraph._paragraphs._removeTextRunCallback?.Invoke(_textRuns[index]); + _textRuns.RemoveAt(index); + } + /// + /// Removes the item from the collection + /// + /// The item to remove + /// + public void Remove(ExcelParagraphTextRunBase item) + { + if (!_textRuns.Contains(item)) + { + throw new ArgumentException("Paragraph item does not exist in the collection"); + } + var pn = item.TopNode; + pn.ParentNode.RemoveChild(pn); + _paragraph._paragraphs._removeTextRunCallback?.Invoke(item); + _textRuns.Remove(item); + } + /// + /// Adds a rich text run with the text. + /// + /// + /// + public ExcelParagraphTextRun Add(string text) + { + var rn = CreateNode("a:r", false, true); + var txtRun = new ExcelParagraphTextRun(_paragraph, NameSpaceManager, rn); + txtRun.Text = text; + + return Add(txtRun); + } + internal ExcelParagraphTextRun Add(ExcelParagraphTextRun txtRun) + { + _textRuns.Add(txtRun); + _paragraph._paragraphs._addCallback?.Invoke(txtRun); + return txtRun; + } + /// + /// Clear all text runs from the collection + /// + public void Clear() + { + for (int i = 0; i < _textRuns.Count; i++) + { + var pn = _textRuns[i].TopNode; + pn.ParentNode.RemoveChild(pn); + _paragraph._paragraphs._removeTextRunCallback?.Invoke(_textRuns[i]); + } + _textRuns.Clear(); + } + /// + /// Returns true if the text run exists in the collection. + /// + /// The paragraph to check for + /// True if exists + public bool Contains(ExcelParagraphTextRunBase item) + { + return _textRuns.Contains(item); + } + /// + /// Returns the index in the collection of the supplied item. + /// + /// The item + /// The index in the collection. + public int IndexOf(ExcelParagraphTextRunBase item) + { + return _textRuns.IndexOf(item); + } + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_textRuns).GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _textRuns.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + internal List ExportToImageRendererFormat() + { + List RtFormatList = new List(); + foreach (var item in _textRuns) + { + RtFormatList.Add(item.ExportToImageRendererFormat()); + } + return RtFormatList; + } + + internal List ExportToOpenTypeFormat() + { + List RtFormatList = new List(); + foreach (var item in _textRuns) + { + RtFormatList.Add(item.ExportToOpenTypeFormat()); + } + return RtFormatList; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/ExcelParagraphLineBreak.cs b/src/EPPlus/Drawing/Style/Text/ExcelParagraphLineBreak.cs new file mode 100644 index 0000000000..297c777709 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelParagraphLineBreak.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 09/15/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Drawing.Interfaces; +using System; +using System.Xml; +namespace OfficeOpenXml.Drawing +{ + public class ExcelParagraphLineBreak : ExcelParagraphTextRunBase + { + internal ExcelParagraphLineBreak(ExcelDrawingParagraph paragraph, XmlNamespaceManager ns, XmlNode topNode) : base(paragraph, ns, topNode) + { + } + public override eParagraphRunType Type => eParagraphRunType.LineBreak; + + public override string Text + { + get + { + return Environment.NewLine; + } + set + { + throw new InvalidOperationException("Can not set the text for a line break paragraph item."); + } + } + } +} diff --git a/src/EPPlus/Drawing/Style/Text/ExcelParagraphTabStop.cs b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTabStop.cs new file mode 100644 index 0000000000..6598d750d5 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTabStop.cs @@ -0,0 +1,74 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using System.Xml; + +namespace OfficeOpenXml.Drawing +{ + /// + /// Describes a tab stop in a paragraphs tab stop collection. + /// + public class ExcelDrawingParagraphTabStop : XmlHelper + { + Action _initXml; + internal ExcelDrawingParagraphTabStop(XmlNamespaceManager nsm, XmlElement topNode, string[] schemaNodeOrder, Action initXml) : base(nsm, topNode) + { + SchemaNodeOrder = schemaNodeOrder; + _initXml= initXml; + } + /// + /// How the text is aligned for a particular tab stop. + /// + public eTabStopParagraphAlignment Alignment + { + get + { + return GetXmlNodeString("@algn").ToEnum(eTabStopParagraphAlignment.Left, new Dictionary + { + ["r"] = eTabStopParagraphAlignment.Right, + ["l"] = eTabStopParagraphAlignment.Left, + ["dec"] = eTabStopParagraphAlignment.Decimal, + ["ctr"] = eTabStopParagraphAlignment.Center + }); + } + set + { + _initXml.Invoke(); + SetXmlNodeString("@algn", value.ToEnumString(new Dictionary + { + [eTabStopParagraphAlignment.Right] = "r", + [eTabStopParagraphAlignment.Left] = "l", + [eTabStopParagraphAlignment.Decimal] = "dec", + [eTabStopParagraphAlignment.Center] = "ctr" + })); + } + } + /// + /// The position of the tab stop relative to the left margin in pixels. + /// + public double Position + { + get + { + return GetXmlNodeEmuToPixel("@pos"); + } + set + { + _initXml.Invoke(); + SetXmlNodeEmuToPixel("@pos", value); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextField.cs b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextField.cs new file mode 100644 index 0000000000..b90c51147e --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextField.cs @@ -0,0 +1,39 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 09/15/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Drawing.Interfaces; +using System.Xml; +namespace OfficeOpenXml.Drawing +{ + /// + /// A regular text run. + /// + public class ExcelParagraphTextField : ExcelParagraphTextRunBase + { + internal ExcelParagraphTextField(ExcelDrawingParagraph paragraph, XmlNamespaceManager ns, XmlNode topNode) : base(paragraph, ns, topNode) + { + } + + public override eParagraphRunType Type => eParagraphRunType.TextField; + public override string Text + { + get + { + return GetXmlNodeString("a:t"); + } + set + { + SetXmlNodeString("a:t", value, true); + } + } + } +} diff --git a/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRun.cs b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRun.cs new file mode 100644 index 0000000000..d31eeeca89 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRun.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 09/15/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Text; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Drawing; +using System.Reflection.Emit; +using System.Xml; +namespace OfficeOpenXml.Drawing +{ + + /// + /// A regular text run. + /// + public class ExcelParagraphTextRun : ExcelParagraphTextRunBase + { + internal ExcelParagraphTextRun(ExcelDrawingParagraph paragraph, XmlNamespaceManager ns, XmlNode topNode) : base(paragraph, ns, topNode) + { + } + public override eParagraphRunType Type => eParagraphRunType.TextRun; + public override string Text + { + get + { + return GetXmlNodeString("a:t"); + } + set + { + //The node must always exist therefore false. + SetXmlNodeString("a:t", value, false); + } + } + } +} diff --git a/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRunBase.cs b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRunBase.cs new file mode 100644 index 0000000000..1f102fbbf8 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/ExcelParagraphTextRunBase.cs @@ -0,0 +1,673 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 09/15/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.DrawingRenderer.RenderItems.Textbox; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Coloring; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Interfaces.RichText; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Xml; +using tc = OfficeOpenXml.Utils.TypeConversion; + +namespace OfficeOpenXml.Drawing +{ + /// + /// A richtext part + /// + public abstract class ExcelParagraphTextRunBase : XmlHelper + { + /// + /// for measuring + /// + string _defaultFontName; + double _defaultFontSize; + ExcelTextFont _dtr; + internal IPictureRelationDocument _prd; + ExcelDrawingParagraph _paragraph; + + internal ExcelParagraphTextRunBase(ExcelDrawingParagraph paragraph, XmlNamespaceManager ns, XmlNode topNode) : base(ns, topNode) + { + SchemaNodeOrder = ["rPr", "pPr", "t"]; + _paragraph = paragraph; + _prd = _paragraph._prd; + //Default properties are always taken from the first paragraph. + if (_paragraph._paragraphs.Count == 0) + { + _dtr = _paragraph.DefaultRunProperties; + } + else + { + _dtr = _paragraph._paragraphs[0].DefaultRunProperties; + } + } + + internal List SplitIntoLines() + { + var strLst = Text.Split("\r\n".ToArray()).ToList(); + return strLst; + } + + internal ExcelDrawingParagraph Paragraph { get => _paragraph; } + /// + /// The type of text run + /// + public abstract eParagraphRunType Type { get; } + + internal MeasurementFont GetMeasurementFont() + { + var test = _prd.Package.Workbook.ThemeManager.GetOrCreateTheme().GetFontByCode(string.IsNullOrEmpty(LatinFont) ? ComplexFont : LatinFont); + var mf = new MeasurementFont() + { + FontFamily = _prd.Package.Workbook.ThemeManager.GetOrCreateTheme().GetFontByCode(string.IsNullOrEmpty(LatinFont) ? ComplexFont : LatinFont), + Size = Baseline == 0 ? FontSize : (float)(FontSize * (1 - (Math.Abs(Baseline) / 100))), + Style = GetFontStyle() + }; + + if (string.IsNullOrEmpty(mf.FontFamily) || mf.Size <= 0 || float.IsNaN(mf.Size)) + { + var defaultMeasurementFont = _paragraph.DefaultRunProperties.GetMeasureFont(); + + if (string.IsNullOrEmpty(mf.FontFamily)) + { + mf.FontFamily = defaultMeasurementFont.FontFamily; + } + + if(mf.Size <= 0 || float.IsNaN(mf.Size)) + { + mf.Size = defaultMeasurementFont.Size; + } + } + + return mf; + } + + private string GetFontName(string fontName) + { + if(fontName.StartsWith("+")) + { + + } + + return fontName; + } + + #region Basic Fill + ExcelDrawingFill _fill; + /// + /// A reference to the fill properties + /// + public ExcelDrawingFill Fill + { + get + { + if (_fill == null) + { + _fill = new ExcelDrawingFill(_prd, NameSpaceManager, TopNode, "a:rPr", SchemaNodeOrder); + } + return _fill; + } + } + + /// + /// Check if textrun has a Fill property as Accessing "Fill" creates a fill + /// + /// + public bool HasFill() + { + return _fill != null; + } + + ////Below is quick-access to the drawing fill + //string _colorPath = "a:rPr/a:solidFill/a:srgbClr/@val"; + ///// + ///// Sets the default color of the text. + ///// This sets the Fill to a SolidFill with the specified color. + ///// + ///// Use the Fill property for more options + ///// + ///// + //public Color Color + //{ + // get + // { + // string col = GetXmlNodeString(_colorPath); + // if (col == "") + // { + // return Color.Empty; + // } + // else + // { + // return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier)); + // } + // } + // set + // { + // Fill.Style = eFillStyle.SolidFill; + // Fill.SolidFill.Color.SetRgbColor(value); + // } + //} + #endregion Basic fill + + //UnderlineLine underlineFill etc. + #region Underline + string _underLineColorSetPath = "a:rPr/a:uFill/a:solidFill/a:srgbClr/@val"; + string _underLineColorPath = "a:rPr/a:uFill/a:solidFill"; + + ExcelDrawingColorManager _underlineColorManager = null; + + /// + /// The fonts underline color + /// + public Color UnderLineColor + { + get + { + if(_underlineColorManager == null) + { + _underlineColorManager = new ExcelDrawingColorManager(NameSpaceManager, TopNode, _underLineColorPath, SchemaNodeOrder); + } + + if(_underlineColorManager.ColorType == eDrawingColorType.Scheme) + { + return tc.ColorConverter.GetThemeColor(_prd.Package.Workbook.ThemeManager.GetOrCreateTheme(), _underlineColorManager); + } + else + { + var col = _underlineColorManager.GetColor(); + return col; + } + } + set + { + if (_underlineColorManager == null) + { + _underlineColorManager = new ExcelDrawingColorManager(NameSpaceManager, TopNode, _underLineColorPath, SchemaNodeOrder); + } + _underlineColorManager.SetRgbColor(value); + } + } + + #endregion Underline + + #region FontNodes + + string _fontLatinPath = "a:rPr/a:latin/@typeface"; + /// + /// The latin typeface name + /// + public string LatinFont + { + get + { + var v=GetXmlNodeString(_fontLatinPath); + if(string.IsNullOrEmpty(v) && _dtr != null) + { + v = _dtr.LatinFont; + } + return v; + } + set + { + SetXmlNodeString(_fontLatinPath, value); + } + } + string _fontEaPath = "a:rPr/a:ea/@typeface"; + /// + /// The East Asian typeface name + /// + public string EastAsianFont + { + get + { + var v = GetXmlNodeString(_fontEaPath); + if (string.IsNullOrEmpty(v) && _dtr != null) + { + v = _dtr.EastAsianFont; + } + return v; + } + set + { + SetXmlNodeString(_fontEaPath, value); + } + } + string _fontCsPath = "a:rPr/a:cs/@typeface"; + /// + /// The complex font typeface name + /// + public string ComplexFont + { + get + { + var v = GetXmlNodeString(_fontCsPath); + if (string.IsNullOrEmpty(v) && _dtr != null) + { + v = _dtr.ComplexFont; + } + return v; + } + set + { + SetXmlNodeString(_fontCsPath, value); + } + } + + string _fontSymPath = "a:rPr/a:sym/@typeface"; + /// + /// The symbol font typeface name + /// + public string SymbolFont + { + get + { + return GetXmlNodeString(_fontSymPath); + } + set + { + SetXmlNodeString(_fontSymPath, value); + } + } + string _boldPath = "a:rPr/@b"; + /// + /// If the font is bold + /// + public bool FontBold + { + get + { + var v=GetXmlNodeBoolNullable(_boldPath); + if(v==null && _dtr != null) + { + v = _dtr.Bold; + } + return v??false; + } + set + { + SetXmlNodeString(_boldPath, value ? "1" : "0"); + } + } + string _underLinePath = "a:rPr/@u"; + /// + /// The fonts underline style + /// + public eUnderLineType FontUnderLine + { + get + { + var v = GetXmlNodeString(_underLinePath)?.TranslateUnderline(); + if (v == null && _dtr != null) + { + v = _dtr.UnderLine; + } + return v ?? eUnderLineType.None; + } + set + { + SetXmlNodeString(_underLinePath, value.TranslateUnderlineText()); + } + } + + string _italicPath = "a:rPr/@i"; + /// + /// If the font is italic + /// + public bool FontItalic + { + get + { + var v = GetXmlNodeBoolNullable(_italicPath); + if (v == null && _dtr != null) + { + v = _dtr.Italic; + } + return v ?? false; + + } + set + { + SetXmlNodeString(_italicPath, value ? "1" : "0"); + } + } + string _strikePath = "a:rPr/@strike"; + /// + /// Font strike out type + /// + public eStrikeType FontStrike + { + get + { + var v = GetXmlNodeString(_strikePath)?.TranslateStrikeType(); + if (v == null && _dtr != null) + { + v = _dtr.Strike; + } + return v ?? eStrikeType.No; + } + set + { + SetXmlNodeString(_strikePath, value.TranslateStrikeTypeText()); + } + } + string _sizePath = "a:rPr/@sz"; + /// + /// Font size + /// + public float FontSize + { + get + { + var v = GetXmlNodeDoubleNull(_sizePath); + if (v == null) + { + if(_dtr == null || _dtr.Size == int.MinValue) + { + return _prd.Package.Workbook.Styles.GetNormalStyle().Style.Font.Size; + } + return _dtr.Size; + } + else + { + return (float)(v / 100); + } + } + set + { + SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString()); + } + } + string _kernPath = "a:rPr/@kern"; + /// + /// Specifies the minimum font size at which character kerning occurs for this text run + /// + public double Kerning + { + get + { + var v = GetXmlNodeDoubleNull(_kernPath); + if(v==null && _dtr != null) + { + return _dtr.Kerning; + } + else + { + return (float)(v / 100); + } + } + set + { + SetXmlNodeFontSize(_kernPath, value, "Kerning"); + } + } + string _capPath = "a:rPr/@cap"; + /// + /// The capitalization that is to be applied + /// + public eTextCapsType Capitalization + { + get + { + var v = GetXmlNodeString(_capPath); + if(string.IsNullOrEmpty(v)) + { + return _dtr?.Capitalization ?? eTextCapsType.None; + } + else + { + switch (v) + { + case "all": + return eTextCapsType.All; + case "small": + return eTextCapsType.Small; + default: + return eTextCapsType.None; + } + } + } + set + { + SetXmlNodeString(_capPath, value.ToEnumString()); + } + } + + string _baselinePath = "a:rPr/@baseline"; + /// + /// The baseline for both the superscript and subscript fonts in percentage + /// + public double Baseline + { + get + { + var v=GetXmlNodePercentage(_baselinePath); + if (v == null && _dtr != null) + { + return _dtr.Baseline; + } + else + { + return v.Value; + } + } + set + { + SetXmlNodePercentage(_baselinePath, value); + } + } + string _highlightPath = "a:rPr/a:highlight"; + /// + /// The highlight color. + /// + public ExcelDrawingColorManager HighlightColor + { + get + { + return new ExcelDrawingColorManager(NameSpaceManager, TopNode, _highlightPath, SchemaNodeOrder); + } + } + string _spacingPath = "a:rPr/@spc"; + public double Spacing + { + get + { + var v = GetXmlNodeDoubleNull(_spacingPath); + if(v==null && _dtr != null) + { + return _dtr.Spacing; + } + else + { + return v.Value / 100; + } + } + set + { + SetXmlNodeDouble(_spacingPath, value * 100); + } + } + /// + /// Set the font style properties + /// + /// Font family name + /// Font size + /// + /// + /// + /// + public void SetFromFont(string name, float size, bool bold = false, bool italic = false, bool underline = false, bool strikeout = false) + { + LatinFont = name; + ComplexFont = name; + FontSize = size; + if (bold) FontBold = bold; + if (italic) FontItalic = italic; + if (underline) FontUnderLine = eUnderLineType.Single; + if (strikeout) FontStrike = eStrikeType.Single; + } + + //internal void GetHeightInPixels(out float textWidth, out float textHeight, string text) + //{ + // var tm = _prd.Package.Settings.TextSettings.PrimaryTextMeasurer; + // _prd.Package.Workbook.Styles.GetNormalStyle(); + // MeasurementFont f = GetMeasureFont(); + // var b = tm.MeasureText(text, f); + // textWidth = b.Width; + // textHeight = b.Height; + //} + internal MeasurementFont GetMeasureFont() + { + var lf = LatinFont; + if (string.IsNullOrEmpty(lf) && _dtr != null) + { + lf = _dtr.LatinFont; + } + var cf = ComplexFont; + if (string.IsNullOrEmpty(cf)) + { + cf = _paragraph.DefaultRunProperties.ComplexFont; + } + var eaf = ComplexFont; + if (string.IsNullOrEmpty(eaf)) + { + eaf = _paragraph.DefaultRunProperties.EastAsianFont; + } + if (double.IsNaN(FontSize)) + { + FontSize = _paragraph.DefaultRunProperties.Size; + } + return FontUtil.GetMeasureFont(lf, cf, eaf, FontSize, GetFontStyle(), _prd.Package); + } + private MeasurementFontStyles GetFontStyle() + { + MeasurementFontStyles ret = MeasurementFontStyles.Regular; + if (FontBold) + { + ret |= MeasurementFontStyles.Bold; + } + if (FontItalic) + { + ret |= MeasurementFontStyles.Italic; + } + if (FontUnderLine != eUnderLineType.None) + { + ret |= MeasurementFontStyles.Underline; + } + return ret; + } + + internal bool IsEmpty + { + get + { + return TopNode == null || (TopNode.ChildNodes.Count == 0 && TopNode.Attributes.Count == 0); + } + } + + #endregion FontNodes + + #region HyperLink + #endregion Hyperlink + + /// + /// Right to left + /// If ommitted it returns false AKA (left-to-right) + /// + internal bool rtl; + + //TODO: + #region ExtLst-OfficeArtExtensionList + #endregion ExtLst-OfficeArtExtensionList + + /// + /// Actual text for the text run + /// + public abstract string Text + { + get; + set; + } + /// + /// If the text item is the first item in the paragraph + /// + public bool IsFirstInParagraph + { + get + { + return _paragraph.TextRuns.IndexOf(this) == 0; + } + } + /// + /// If the text item is the last item in the paragraph + /// + public bool IsLastInParagraph + { + get + { + return _paragraph.TextRuns.IndexOf(this) == _paragraph.TextRuns.Count-1; + } + } + + /// + /// Export to OpenTypeFormat + /// + /// + internal IRichTextFormatEssential ExportToOpenTypeFormat() + { + var measureFont = GetMeasurementFont(); + var rtBase = new RichTextFormatBase(Text, measureFont.FontFamily, measureFont.Size, FontBold, FontItalic); + return rtBase; + } + + /// + /// Export to OpenTypeFormat + /// + /// + internal IRichTextFormatDrawing ExportToImageRendererFormat() + { + //This is neccesary for the baseline to be applied to the fontsize correctly + var measureFont = GetMeasurementFont(); + + var rtBase = new RichTextFormatDrawing(Text, measureFont.FontFamily, measureFont.Size, FontBold, FontItalic); + + switch (Capitalization) + { + case eTextCapsType.All: + rtBase.Text = Text.ToUpper(); + break; + case eTextCapsType.Small: + rtBase.Text = Text.ToLower(); + break; + default: + //Leave as is + break; + + } + + rtBase.Capitalization = (int)Capitalization; + rtBase.HighLightColor = HighlightColor.GetColor(); + rtBase.FontColor = Fill.Color; + rtBase.UnderlineColor = UnderLineColor; + rtBase.Baseline = Baseline; + rtBase.Spacing = Spacing; + return rtBase; + } + } +} diff --git a/src/EPPlus/Drawing/Style/Text/ExcelTextBody.cs b/src/EPPlus/Drawing/Style/Text/ExcelTextBody.cs index ae0635b038..5ee1c7bb0b 100644 --- a/src/EPPlus/Drawing/Style/Text/ExcelTextBody.cs +++ b/src/EPPlus/Drawing/Style/Text/ExcelTextBody.cs @@ -10,10 +10,12 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Xml; +using OfficeOpenXml.Drawing.Interfaces; using OfficeOpenXml.Style; using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.IO; +using System.Xml; namespace OfficeOpenXml.Drawing { @@ -24,11 +26,24 @@ public class ExcelTextBody : XmlHelper { private readonly string _path; private readonly Action _initXml; - internal ExcelTextBody(XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder=null, Action initXml=null) : + internal readonly IPictureRelationDocument _pictureRelationDocument; + + /// + /// Represents the TextBody AND the TextbodyProperties node (?) + /// + /// + /// + /// + /// + /// + /// + internal ExcelTextBody(IPictureRelationDocument pictureRelationDocument, XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder=null, Action initXml=null) : base(ns, topNode) { + _pictureRelationDocument = pictureRelationDocument; _path = path; - _initXml = initXml; + + _initXml = initXml; AddSchemaNodeOrder(schemaNodeOrder, new string[] { "ln", "noFill", "solidFill", "gradFill", "pattFill", "blipFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "extLst", "highlight", "kumimoji", "lang", "altLang", "sz", "b", "i", "u", "strike", "kern", "cap", "spc", "normalizeH", "baseline", "noProof", "dirty", "err", "smtClean", "smtId", "bmk" }); } /// @@ -84,7 +99,7 @@ public eUnderLineType UnderLine } } /// - /// The bottom inset of the bounding rectangle + /// The bottom inset of the bounding rectangle. Default value if this property is null is 45720. /// public double? BottomInsert { @@ -99,7 +114,7 @@ public double? BottomInsert } } /// - /// The top inset of the bounding rectangle + /// The top inset of the bounding rectangle. Default value if this property is null is 45720. /// public double? TopInsert { @@ -114,7 +129,7 @@ public double? TopInsert } } /// - /// The right inset of the bounding rectangle + /// The right inset of the bounding rectangle. Default value if this property is null is 91440. /// public double? RightInsert { @@ -129,7 +144,7 @@ public double? RightInsert } } /// - /// The left inset of the bounding rectangle + /// The left inset of the bounding rectangle. Default value if this property is null is 91440. /// public double? LeftInsert { @@ -345,7 +360,7 @@ public eTextAutofit TextAutofit case eTextAutofit.ShapeAutofit: DeleteNode($"{_path}/a:noAutofit"); DeleteNode($"{_path}/a:normAutofit"); - CreateNode($"{_path}/a:spAutofit"); + CreateNode($"{_path}/a:spAutoFit"); break; case eTextAutofit.NoAutofit: DeleteNode($"{_path}/a:spAutoFit"); @@ -412,5 +427,62 @@ internal void SetFromXml(XmlElement copyFromElement) element.SetAttribute(a.Name, a.NamespaceURI, a.Value); } } + + //Excel default values for Top/Bottom and Right/Left translated to points + //They are equivalent to 0.25cm and 0.13cm + internal const double DefaultTopBot = 45720d / ExcelDrawing.EMU_PER_POINT; + internal const double DefaultRightLeft = 91440d / ExcelDrawing.EMU_PER_POINT; + + /// + /// Get Insets in points + /// + /// + /// + /// + /// + internal void GetInsetsOrDefaults(out double left, out double top, out double right, out double bottom) + { + left = LeftInsert ?? DefaultRightLeft; + top = TopInsert ?? DefaultRightLeft; + right = RightInsert ?? DefaultTopBot; + bottom = BottomInsert ?? DefaultTopBot; + } + + internal void GetInsetsInPoints(out double left, out double top, out double right, out double bottom) + { + left = (LeftInsert ?? 0); + top = (TopInsert ?? 0); + right = (RightInsert ?? 0); + bottom = (BottomInsert ?? 0); + } + + ExcelDrawingParagraphCollection _paragraphs = null; + /// + /// A collection of paragraphs within a rich text in a drawing object. + /// + public ExcelDrawingParagraphCollection Paragraphs + { + get + { + if(_paragraphs==null) + { + var textBodyPath = _path.Substring(0, _path.LastIndexOf('/')); + _paragraphs = new ExcelDrawingParagraphCollection(_pictureRelationDocument, NameSpaceManager, TopNode, textBodyPath, SchemaNodeOrder, _initXml); + } + return _paragraphs; + } + } + /// + /// Excel always creates textbodies with an empty paragraph if none exist. + /// We add one on save to avoid confusing the user + /// As otherwise there would always be a dummy paragraph at Paragraph[0] + /// + internal void SaveTextBody() + { + if (Paragraphs.Count == 0) + { + Paragraphs.Add(""); + } + } } } diff --git a/src/EPPlus/Drawing/Style/Text/ExcelTextRun.cs b/src/EPPlus/Drawing/Style/Text/ExcelTextRun.cs index c1433c5548..9d34ebe710 100644 --- a/src/EPPlus/Drawing/Style/Text/ExcelTextRun.cs +++ b/src/EPPlus/Drawing/Style/Text/ExcelTextRun.cs @@ -10,171 +10,90 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System.Xml; -using OfficeOpenXml.Style; -using OfficeOpenXml.Utils.EnumUtils; namespace OfficeOpenXml.Drawing { /// /// A richtext part /// - public class ExcelTextRun : XmlHelper - { - string _path; - internal ExcelTextRun(XmlNamespaceManager ns, XmlNode topNode, string path) : - base(ns, topNode) - { - _path = path; - SchemaNodeOrder = new string[] { "ln", "noFill", "solidFill", "gradFill", "pattFill", "blipFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "extLst", "highlight", "kumimoji", "lang", "altLang", "sz", "b", "i", "u", "strike", "kern", "cap", "spc", "normalizeH", "baseline", "noProof", "dirty", "err", "smtClean", "smtId", "bmk" }; - } - /// - /// The capitalization that is to be applied - /// - public eTextCapsType Capitalization - { - get - { - return GetXmlNodeString($"{_path}/@cap").ToEnum(eTextCapsType.None); - } - set - { - SetXmlNodeString($"{_path}/@kern", value.ToEnumString()); - } - } - /// - /// The minimum font size at which character kerning occurs - /// - public double Kerning - { - get - { - return GetXmlNodeFontSize($"{_path}/@kern"); - } - set - { - SetXmlNodeFontSize($"{_path}/@kern", value, "Kerning"); - } - } - /// - /// Fontsize - /// Spans from 0-4000 - /// - public double FontSize - { - get - { - return GetXmlNodeFontSize($"{_path}/@sz"); - } - set - { - SetXmlNodeFontSize($"{_path}/@sz", value, "FontSize"); - } - } - /// - /// The spacing between between characters - /// - public double Spacing - { - get - { - return GetXmlNodeFontSize($"{_path}/@spc"); - } - set - { - SetXmlNodeFontSize($"{_path}/@spc", value, "Spacing", true); - } - } - /// - /// The baseline for both the superscript and subscript fonts in percentage - /// - public double Baseline - { - get - { - return GetXmlNodePercentage($"{_path}/@baseline")??0; - } - set - { - SetXmlNodePercentage($"{_path}/@baseline", value); - } - } - /// - /// Bold text - /// - public bool Bold - { - get - { - return GetXmlNodeBool($"{_path}/@b"); - } - set - { - SetXmlNodeBool($"{_path}/@b", value, false); - } - } - /// - /// Italic text - /// - public bool Italic - { - get - { - return GetXmlNodeBool($"{_path}/@i"); - } - set - { - SetXmlNodeBool($"{_path}/@i", value, false); - } - } - /// - /// Strike-out text - /// - public eStrikeType Strike - { - get - { - return GetXmlNodeString($"{_path}/@strike").TranslateStrikeType(); - } - set - { - SetXmlNodeString($"{_path}/@strike", value.TranslateStrikeTypeText()); - } - } - /// - /// Underlined text - /// - public eUnderLineType UnderLine - { - get - { - return GetXmlNodeString($"{_path}/@u").TranslateUnderline(); - } - set - { - if (value == eUnderLineType.None) - { - DeleteNode($"{_path}/@u"); - } - else - { - SetXmlNodeString($"{_path}/@u", value.TranslateUnderlineText()); - } - } - } - internal XmlElement PathElement - { - get - { - var node = (XmlElement)GetNode(_path); - if (node == null) - { - return (XmlElement)CreateNode(_path); - } - else - { - return node; - } - } - } - } + // public class ExcelTextRun : XmlHelper + // { + // string _path; + // internal ExcelTextRun(XmlNamespaceManager ns, XmlNode topNode, string path) : + // base(ns, topNode) + // { + // _path = path; + // SchemaNodeOrder = new string[] { "ln", "noFill", "solidFill", "gradFill", "pattFill", "blipFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "extLst", "highlight", "kumimoji", "lang", "altLang", "sz", "b", "i", "u", "strike", "kern", "cap", "spc", "normalizeH", "baseline", "noProof", "dirty", "err", "smtClean", "smtId", "bmk" }; + // Properties = new ExcelRegularTextRun(); + // } + + // ExcelParagraphTextRun Properties; + + // #region Attributes + // /// + // /// FontBold text + // /// + // public bool FontBold { get => Properties.Attributes.FontBold; set => Properties.Attributes.FontBold = value; } + + + // /// + // /// The baseline for both the superscript and subscript fonts in percentage + // /// + // public double Baseline { get => Properties.Attributes.Baseline; set => Properties.Attributes.Baseline = value; } + + // /// + // /// The capitalization that is to be applied + // /// + // public eTextCapsType Capitalization { get => Properties.Attributes.Capitalization; set => Properties.Attributes.Capitalization = value; } + // //TODO: Dirty + + // //TODO: err (spelling error) + + // /// + // /// FontItalic text + // /// + // public bool FontItalic { get => Properties.Attributes.FontItalic; set => Properties.Attributes.FontItalic = value; } + + // /// + // /// The minimum font size at which character kerning occurs + // /// + // public double Kerning { get => Properties.Attributes.Kerning; set => Properties.Attributes.Kerning = value; } + + // public double Spacing { get => Properties.Attributes.Spacing; set => Properties.Attributes.Spacing = value; } + + // /// + // /// FontStrike-out text + // /// + // public eStrikeType FontStrike { get => Properties.Attributes.FontStrike; set => Properties.Attributes.FontStrike = value; } + + // /// + // /// Fontsize + // /// Spans from 0-4000 + // /// + // public double FontSize { get => Properties.Attributes.FontSize; set => Properties.Attributes.FontSize = (float)value; } + + // /// + // /// Underlined text + // /// + // public eUnderLineType FontUnderLine { get => Properties.Attributes.FontUnderLine; set => Properties.Attributes.FontUnderLine = value; } + + // #endregion Attributes + + + + // internal XmlElement PathElement + // { + // get + // { + // var node = (XmlElement)GetNode(_path); + // if (node == null) + // { + // return (XmlElement)CreateNode(_path); + // } + // else + // { + // return node; + // } + // } + // } + //} } diff --git a/src/EPPlus/Drawing/Style/Text/TempTextBodyProperties.cs b/src/EPPlus/Drawing/Style/Text/TempTextBodyProperties.cs new file mode 100644 index 0000000000..4cb699aab0 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/TempTextBodyProperties.cs @@ -0,0 +1,407 @@ +using System; +using System.Xml; +using OfficeOpenXml.Style; +using OfficeOpenXml.Utils.EnumUtils; + + +namespace OfficeOpenXml.Drawing.Style.Text +{ + internal class TempTextBodyProperties : XmlHelper + { + private readonly string _path; + private readonly Action _initXml; + internal TempTextBodyProperties(XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder = null, Action initXml = null) : + base(ns, topNode) + { + _path = path; + _initXml = initXml; + AddSchemaNodeOrder(schemaNodeOrder, new string[] { "ln", "noFill", "solidFill", "gradFill", "pattFill", "blipFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "extLst", "highlight", "kumimoji", "lang", "altLang", "sz", "b", "i", "u", "strike", "kern", "cap", "spc", "normalizeH", "baseline", "noProof", "dirty", "err", "smtClean", "smtId", "bmk" }); + } + /// + /// The anchoring position within the shape + /// + public eTextAnchoringType Anchor + { + get + { + return GetXmlNodeString($"{_path}/@anchor").TranslateTextAchoring(); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@anchor", value.TranslateTextAchoringText()); + } + } + /// + /// The centering of the text box. + /// + public bool AnchorCenter + { + get + { + return GetXmlNodeBool($"{_path}/@anchorCtr"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@anchorCtr", value, false); + } + } + /// + /// Underlined text + /// + public eUnderLineType UnderLine + { + get + { + return GetXmlNodeString($"{_path}/@u").TranslateUnderline(); + } + set + { + if (value == eUnderLineType.None) + { + DeleteNode($"{_path}/@u"); + } + else + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@u", value.TranslateUnderlineText()); + } + } + } + /// + /// The bottom inset of the bounding rectangle. Default value if this property is null is 45720. + /// + public double? BottomInsert + { + get + { + return GetXmlNodeEmuToPtNull($"{_path}/@bIns"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPt($"{_path}/@bIns", value); + } + } + /// + /// The top inset of the bounding rectangle. Default value if this property is null is 45720. + /// + public double? TopInsert + { + get + { + return GetXmlNodeEmuToPtNull($"{_path}/@tIns"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPt($"{_path}/@tIns", value); + } + } + /// + /// The right inset of the bounding rectangle. Default value if this property is null is 91440. + /// + public double? RightInsert + { + get + { + return GetXmlNodeEmuToPtNull($"{_path}/@rIns"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPt($"{_path}/@rIns", value); + } + } + /// + /// The left inset of the bounding rectangle. Default value if this property is null is 91440. + /// + public double? LeftInsert + { + get + { + return GetXmlNodeEmuToPtNull($"{_path}/@lIns"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeEmuToPt($"{_path}/@lIns", value); + } + } + /// + /// The rotation that is being applied to the text within the bounding box + /// + public double? Rotation + { + get + { + return GetXmlNodeAngle($"{_path}/@rot"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeAngle($"{_path}/@rot", value, "Rotation", -100000, 100000); + } + } + /// + /// The space between text columns in the text area + /// + public double SpaceBetweenColumns + { + get + { + return GetXmlNodeEmuToPt($"{_path}/@spcCol"); + } + set + { + if (value < 0) throw new ArgumentOutOfRangeException("SpaceBetweenColumns", "Can't be negative"); + _initXml?.Invoke(); + SetXmlNodeEmuToPt($"{_path}/@spcCol", value); + } + } + + /// + /// If the before and after paragraph spacing defined by the user is to be respected + /// + public bool ParagraphSpacing + { + get + { + return GetXmlNodeBool($"{_path}/@spcFirstLastPara"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@spcFirstLastPara", value); + } + } + /// + /// + /// + public bool TextUpright + { + get + { + return GetXmlNodeBool($"{_path}/@upright"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@upright", value); + } + } + /// + /// If the line spacing is decided in a simplistic manner using the font scene + /// + public bool CompatibleLineSpacing + { + get + { + return GetXmlNodeBool($"{_path}/@compatLnSpc"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@compatLnSpc", value); + } + } + /// + /// Forces the text to be rendered anti-aliased + /// + public bool ForceAntiAlias + { + get + { + return GetXmlNodeBool($"{_path}/@forceAA"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@forceAA", value); + } + } + /// + /// If the text within this textbox is converted from a WordArt object. + /// + public bool FromWordArt + { + get + { + return GetXmlNodeBool($"{_path}/@fromWordArt"); + } + set + { + _initXml?.Invoke(); + SetXmlNodeBool($"{_path}/@fromWordArt", value); + } + } + /// + /// If the text should be displayed vertically + /// + public eTextVerticalType VerticalText + { + get + { + return GetXmlNodeString($"{_path}/@vert").TranslateTextVertical(); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@vert", value.TranslateTextVerticalText()); + } + } + /// + /// If the text can flow out horizontaly + /// + public eTextHorizontalOverflow HorizontalTextOverflow + { + get + { + return GetXmlNodeString($"{_path}/@horzOverflow").ToEnum(eTextHorizontalOverflow.Overflow); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@horzOverflow", value.ToEnumString()); + } + } + + /// + /// If the text can flow out of the bounding box vertically + /// + public eTextVerticalOverflow VerticalTextOverflow + { + get + { + return GetXmlNodeString($"{_path}/@vertOverflow").ToEnum(eTextVerticalOverflow.Overflow); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@vertOverflow", value.ToEnumString()); + } + } + /// + /// How text is wrapped + /// + public eTextWrappingType WrapText + { + get + { + return GetXmlNodeString($"{_path}/@wrap").ToEnum(eTextWrappingType.Square); + } + set + { + _initXml?.Invoke(); + SetXmlNodeString($"{_path}/@wrap", value.ToEnumString()); + } + } + /// + /// The text within the text body should be normally auto-fited + /// + public eTextAutofit TextAutofit + { + get + { + if (ExistsNode($"{_path}/a:normAutofit")) + { + return eTextAutofit.NormalAutofit; + } + else if (ExistsNode($"{_path}/a:spAutoFit")) + { + return eTextAutofit.ShapeAutofit; + } + else + { + return eTextAutofit.NoAutofit; + } + } + set + { + _initXml?.Invoke(); + switch (value) + { + case eTextAutofit.NormalAutofit: + if (value == TextAutofit) return; + DeleteNode($"{_path}/a:spAutoFit"); + DeleteNode($"{_path}/a:noAutofit"); + CreateNode($"{_path}/a:normAutofit"); + break; + case eTextAutofit.ShapeAutofit: + DeleteNode($"{_path}/a:noAutofit"); + DeleteNode($"{_path}/a:normAutofit"); + CreateNode($"{_path}/a:spAutofit"); + break; + case eTextAutofit.NoAutofit: + DeleteNode($"{_path}/a:spAutoFit"); + DeleteNode($"{_path}/a:normAutofit"); + CreateNode($"{_path}/a:noAutofit"); + break; + } + } + } + /// + /// The percentage of the original font size to which each run in the text body is scaled. + /// This propery only applies when the TextAutofit property is set to NormalAutofit + /// + public double? AutofitNormalFontScale + { + get + { + return GetXmlNodePercentage($"{_path}/a:normAutofit/@fontScale"); + } + set + { + if (TextAutofit != eTextAutofit.NormalAutofit) throw new ArgumentException("AutofitNormalFontScale", "TextAutofit must be set to NormalAutofit to use set this property"); + _initXml?.Invoke(); + SetXmlNodePercentage($"{_path}/a:normAutofit/@fontScale", value, false); + } + } + /// + /// The percentage by which the line spacing of each paragraph is reduced. + /// This propery only applies when the TextAutofit property is set to NormalAutofit + /// + public double? LineSpaceReduction + { + get + { + return GetXmlNodePercentage($"{_path}/a:normAutofit/@lnSpcReduction"); + } + set + { + if (TextAutofit != eTextAutofit.NormalAutofit) throw new ArgumentException("LineSpaceReduction", "TextAutofit must be set to NormalAutofit to use set this property"); + _initXml?.Invoke(); + SetXmlNodePercentage($"{_path}/a:normAutofit/@lnSpcReduction", value, false); + } + } + internal XmlElement PathElement + { + get + { + var node = (XmlElement)GetNode(_path); + if (node == null) + { + return (XmlElement)CreateNode(_path); + } + else + { + return node; + } + } + } + internal void SetFromXml(XmlElement copyFromElement) + { + var element = PathElement; + foreach (XmlAttribute a in copyFromElement.Attributes) + { + element.SetAttribute(a.Name, a.NamespaceURI, a.Value); + } + } + + //Excel default values for Top/Bottom and Right/Left in EMU + //They are equivalent to 0.25cm and 0.13cm + internal const double DefaultMarginY = 45720d / ExcelDrawing.EMU_PER_POINT; + internal const double DefaultMarginX = 91440d / ExcelDrawing.EMU_PER_POINT; + } +} diff --git a/src/EPPlus/Drawing/Style/Text/TextCharacterAttributes.cs b/src/EPPlus/Drawing/Style/Text/TextCharacterAttributes.cs new file mode 100644 index 0000000000..f31fddc0c4 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/TextCharacterAttributes.cs @@ -0,0 +1,150 @@ +using OfficeOpenXml.Style; +using System; + +namespace OfficeOpenXml.Drawing.Style.Text +{ + internal class TextCharacterAttributes + { + internal TextCharacterAttributes() + { + + } + + /// + /// Specifies alt language for UI + /// + internal string AltLang; + + /// + /// If the font is bold + /// + public bool Bold; + + /// + /// Baseline for superscript and subscript + /// Based on percentage of the fontsize + /// + public double Baseline; + + /// + /// References link targetname for CustomXML link properties + /// + internal string BMK; + + public eTextCapsType Capitalization; + + /// + /// Flag for checking spelling grammar etc + /// Note: Should probably be set whenever user changes the node text in epplus. + /// + internal bool Dirty; + + /// + /// Performance improvement. No need to spell-check if already known to be misspelled. + /// + internal bool SpellingError; + + /// + /// If the font is italic + /// + public bool Italic; + + double _kerning; + + public double Kerning + { + get + { + return _kerning / 100d; + } + set + { + if (value < 0 || value > 4000) throw new ArgumentOutOfRangeException("kerning", "Fontsize must be between 0 and 4000"); + _kerning = value * 100d; + } + } + + /// + /// If numbers continue vertically with vertical text or stay horizontal + /// (If numbers are to be put in a single character block) + /// Mostly relevant for east asian languages. + /// + public bool Kumimoji; + + /// + /// Language to be used for UI controls. + /// Overriden if alt-lang is set. + /// + internal string LanguageID; + + /// + /// True specifies no spell or grammar check + /// Default false. + /// + internal bool NoProof; + + /// + /// Render-Only modification + /// Wheter to normalize height when rendering. + /// Only changes visuals changes no actual values. + /// False by default + /// + internal bool NormalizeH; + + /// + /// Has this run been checked for smart tags + /// + internal bool SmartTagClean; + + /// + /// Maps to some smart tag e.g. maps to a stock ticker symbol + /// + internal uint SmartTagID; + + /// + /// Spacing between characters usually in 100s of a point + /// Could technically also be a string including another unit of measurment see (ST_TextPoint) + /// + internal double Spacing; + + /// + /// Font strike out type + /// + public eStrikeType Strike; + + //Minimum value is 100 or 1pt + internal double RealSize = -1; + + /// + /// Font size in points + /// Maximum size 4000pts. Minimum 1pt + /// will be clamped if set to larger + /// + public double Size + { + get + { + if (RealSize == -1) RealSize = 1; + return RealSize / 100f; + } + set + { + var input = value; + if (input < 1) + { + input = 1; + } + else if (input > 4000) + { + input = 4000; + } + RealSize = value * 100; + } + } + + /// + /// Specifies wheter to underline the text + /// + public eUnderLineType UnderLine; + } +} diff --git a/src/EPPlus/Drawing/Style/Text/WritingExtension.cs b/src/EPPlus/Drawing/Style/Text/WritingExtension.cs new file mode 100644 index 0000000000..216582343d --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/WritingExtension.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.WritingExtension +{ + internal static class WritingExtension + { + /// + /// Act if not null + /// + /// + /// + /// + internal static bool TryAct(this T param, Action method) + { + if (param != null) + { + method(param); + return true; + } + return false; + } + } +} + diff --git a/src/EPPlus/Drawing/Style/Text/eParagraphRunType.cs b/src/EPPlus/Drawing/Style/Text/eParagraphRunType.cs new file mode 100644 index 0000000000..c8c339a379 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/eParagraphRunType.cs @@ -0,0 +1,30 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + public enum eParagraphRunType + { + /// + /// A regular text run + /// + TextRun, + /// + /// A text field containing generated text. + /// + TextField, + /// + /// A line break + /// + LineBreak + } +} diff --git a/src/EPPlus/Drawing/Style/Text/eTabStopParagraphAlignment.cs b/src/EPPlus/Drawing/Style/Text/eTabStopParagraphAlignment.cs new file mode 100644 index 0000000000..7b29f8e650 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/eTabStopParagraphAlignment.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 9/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + /// + /// Text tab alignment within a single paragraph. + /// + public enum eTabStopParagraphAlignment + { + /// + /// The text at this tab stop is center aligned. + /// + Center, + /// + /// At this tab stop, the decimals are lined up. From a user's point of view, the text here behaves as right aligned until the decimal, and then as left aligned after the decimal. + /// + Decimal, + /// + /// The text at this tab stop is left aligned. + /// + Left, + /// + /// The text at this tab stop is right aligned. + /// + Right + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/Style/Text/eTextFontAlingmentType.cs b/src/EPPlus/Drawing/Style/Text/eTextFontAlingmentType.cs new file mode 100644 index 0000000000..d7139667e6 --- /dev/null +++ b/src/EPPlus/Drawing/Style/Text/eTextFontAlingmentType.cs @@ -0,0 +1,41 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing +{ + /// + /// How characters are aligned vertically. + /// + public enum eTextFontAlingmentType + { + /// + /// When the text flow is horizontal or simple vertical same as fontBaseline but for other vertical modes same as fontCenter. + /// + Automatic, + /// + /// The letters are anchored to the very bottom of a single line. This is different than the bottom baseline because of letters such as "g," "q," "y," etc. + /// + Bottom, + /// + /// The letters are anchored to the bottom baseline of a single line. + /// + Baseline, + /// + /// The letters are anchored between the two baselines of a single line. + /// + Center, + /// + /// The letters are anchored to the top baseline of a single line. + /// + Top + } +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/SvgRenderOptions.cs b/src/EPPlus/Drawing/SvgRenderOptions.cs new file mode 100644 index 0000000000..a984fa65d6 --- /dev/null +++ b/src/EPPlus/Drawing/SvgRenderOptions.cs @@ -0,0 +1,26 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing.Svg +{ + /// + /// Options for rendering drawings to svg. + /// + public class SvgRenderOptions + { + /// + /// The size of the svg image, if you want to override the default size. + /// + public SvgSize Size { get; } = new SvgSize(); + } + +} \ No newline at end of file diff --git a/src/EPPlus/Drawing/SvgSize.cs b/src/EPPlus/Drawing/SvgSize.cs new file mode 100644 index 0000000000..89fdf276a6 --- /dev/null +++ b/src/EPPlus/Drawing/SvgSize.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 01/27/2020 EPPlus Software AB Initial release EPPlus 5 + *************************************************************************************************/ +namespace OfficeOpenXml.Drawing.Svg +{ + public class SvgSize + { + /// + /// Overrides the width for ouput the svg image. + /// + public double? Width { get; set; } = null; + /// + /// Overrides the height of the ouput svg drawing. + /// + public double? Height { get; set; } = null; + public SvgSizeUnit Unit { get; set; } = SvgSizeUnit.Pixels; + } +} + + public enum SvgSizeUnit + { + Pixels=0, + Points=1, + + } diff --git a/src/EPPlus/Drawing/Theme/ExcelColorScheme.cs b/src/EPPlus/Drawing/Theme/ExcelColorScheme.cs index eaa3ccdd69..23e8408bac 100644 --- a/src/EPPlus/Drawing/Theme/ExcelColorScheme.cs +++ b/src/EPPlus/Drawing/Theme/ExcelColorScheme.cs @@ -46,6 +46,45 @@ public ExcelDrawingThemeColorManager Dark1 return _dk1; } } + internal ExcelDrawingThemeColorManager GetColorByEnum(eSchemeColor color) + { + switch (color) + { + case eSchemeColor.Accent1: + return Accent1; + case eSchemeColor.Accent2: + return Accent2; + case eSchemeColor.Accent3: + return Accent3; + case eSchemeColor.Accent4: + return Accent4; + case eSchemeColor.Accent5: + return Accent5; + case eSchemeColor.Accent6: + return Accent6; + case eSchemeColor.Background1: + return Light1; + case eSchemeColor.Background2: + return Light2; + case eSchemeColor.Text1: + return Dark1; + case eSchemeColor.Text2: + return Dark2; + case eSchemeColor.Hyperlink: + return Hyperlink; + case eSchemeColor.FollowedHyperlink: + return FollowedHyperlink; + case eSchemeColor.Light1: + return Light1; + case eSchemeColor.Light2: + return Light2; + case eSchemeColor.Dark1: + return Dark1; + case eSchemeColor.Dark2: + return Dark2; + } + throw (new ArgumentOutOfRangeException($"Type {color} is unhandled.")); + } internal ExcelDrawingThemeColorManager GetColorByEnum(eThemeSchemeColor color) { @@ -74,7 +113,7 @@ internal ExcelDrawingThemeColorManager GetColorByEnum(eThemeSchemeColor color) case eThemeSchemeColor.Hyperlink: return Hyperlink; case eThemeSchemeColor.FollowedHyperlink: - return FollowedHyperlink; + return FollowedHyperlink; } throw(new ArgumentOutOfRangeException($"Type {color} is unhandled.")); } diff --git a/src/EPPlus/Drawing/Theme/ExcelDrawingEffectStyles.cs b/src/EPPlus/Drawing/Theme/ExcelDrawingEffectStyles.cs index a8f980f3c3..fcb97b65bf 100644 --- a/src/EPPlus/Drawing/Theme/ExcelDrawingEffectStyles.cs +++ b/src/EPPlus/Drawing/Theme/ExcelDrawingEffectStyles.cs @@ -30,7 +30,7 @@ internal ExcelThemeEffectStyles(XmlNamespaceManager nameSpaceManager, XmlNode to { _theme = theme; _list = new List(); - foreach (XmlNode node in topNode.ChildNodes) + foreach (XmlElement node in topNode.ChildNodes) { _list.Add(new ExcelThemeEffectStyle(nameSpaceManager, node, "", null, _theme)); } diff --git a/src/EPPlus/Drawing/Theme/ExcelTheme.cs b/src/EPPlus/Drawing/Theme/ExcelTheme.cs index 520619af04..6129b42120 100644 --- a/src/EPPlus/Drawing/Theme/ExcelTheme.cs +++ b/src/EPPlus/Drawing/Theme/ExcelTheme.cs @@ -20,6 +20,7 @@ Date Author Change using OfficeOpenXml.Utils; using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Font; namespace OfficeOpenXml.Drawing.Theme { @@ -49,5 +50,38 @@ internal ExcelTheme(ExcelWorkbook workbook, ZipPackageRelationship rel) { _wb = workbook; } + + internal string GetFontByCode(string fontName) + { + string fontNameTheme; + switch (fontName) + { + case "+mj-lt": + fontNameTheme = FontScheme.MajorFont.FirstOrDefault(x=>(x as ExcelDrawingFontSpecial)?.Type==eFontType.Latin)?.Typeface ?? "Aptos Display"; + break; + case "+mn-lt": + fontNameTheme = FontScheme.MinorFont.FirstOrDefault(x => (x as ExcelDrawingFontSpecial)?.Type == eFontType.Latin)?.Typeface ?? "Aptos Narrow"; + break; + case "+mj-ea": + fontNameTheme = FontScheme.MajorFont.FirstOrDefault(x => (x as ExcelDrawingFontSpecial)?.Type == eFontType.EastAsian)?.Typeface; + if (string.IsNullOrEmpty(fontNameTheme)) return GetFontByCode("+mj-lt"); + break; + case "+mn-ea": + fontNameTheme = FontScheme.MinorFont.FirstOrDefault(x => (x as ExcelDrawingFontSpecial)?.Type == eFontType.EastAsian)?.Typeface; + if (string.IsNullOrEmpty(fontNameTheme)) return GetFontByCode("+mn-lt"); + break; + case "+mj-cs": + fontNameTheme = FontScheme.MajorFont.FirstOrDefault(x => (x as ExcelDrawingFontSpecial)?.Type == eFontType.Complex)?.Typeface; + if (string.IsNullOrEmpty(fontNameTheme)) return GetFontByCode("+mj-lt"); + break; + case "+mn-cs": + fontNameTheme = FontScheme.MinorFont.FirstOrDefault(x => (x as ExcelDrawingFontSpecial)?.Type == eFontType.Complex)?.Typeface; + if (string.IsNullOrEmpty(fontNameTheme)) return GetFontByCode("+mn-lt"); + break; + default: + return fontName; + } + return fontNameTheme; + } } } diff --git a/src/EPPlus/Drawing/Theme/ExcelThemeFillStyles.cs b/src/EPPlus/Drawing/Theme/ExcelThemeFillStyles.cs index 75ceda3aba..57494466c5 100644 --- a/src/EPPlus/Drawing/Theme/ExcelThemeFillStyles.cs +++ b/src/EPPlus/Drawing/Theme/ExcelThemeFillStyles.cs @@ -28,7 +28,7 @@ public class ExcelThemeFillStyles : XmlHelper, IEnumerable internal ExcelThemeFillStyles(XmlNamespaceManager nameSpaceManager, XmlNode topNode, ExcelThemeBase theme) : base(nameSpaceManager, topNode) { _list = new List(); - foreach (XmlNode node in topNode.ChildNodes) + foreach (XmlElement node in topNode.ChildNodes) { _list.Add(new ExcelDrawingFill(theme, nameSpaceManager, node, "", SchemaNodeOrder)); } diff --git a/src/EPPlus/Drawing/Theme/ExcelThemeFontCollection.cs b/src/EPPlus/Drawing/Theme/ExcelThemeFontCollection.cs index c2e9487486..41fe962af4 100644 --- a/src/EPPlus/Drawing/Theme/ExcelThemeFontCollection.cs +++ b/src/EPPlus/Drawing/Theme/ExcelThemeFontCollection.cs @@ -30,7 +30,7 @@ public class ExcelThemeFontCollection : XmlHelper, IEnumerable + /// Gets the first latin font for the theme in this collection. If no font exists, null is returned. + /// + public ExcelDrawingFontSpecial LatinFont + { + get + { + return _lst.FirstOrDefault(x => x is ExcelDrawingFontSpecial f && f.Type == eFontType.Latin) as ExcelDrawingFontSpecial; + } + } + /// + /// Gets the first complex font for the theme in this collection. If no font exists, null is returned. + /// + public ExcelDrawingFontSpecial ComplexFont + { + get + { + return _lst.FirstOrDefault(x => x is ExcelDrawingFontSpecial f && f.Type == eFontType.Complex) as ExcelDrawingFontSpecial; + } + } + /// + /// Gets the first east asian font for the theme in this collection. If no font exists, null is returned. + /// + public ExcelDrawingFontSpecial EastAsianFont + { + get + { + return _lst.FirstOrDefault(x => x is ExcelDrawingFontSpecial f && f.Type == eFontType.EastAsian) as ExcelDrawingFontSpecial; + } + } /// /// Gets an enumerator for the collection /// diff --git a/src/EPPlus/Drawing/Theme/ExcelThemeLine.cs b/src/EPPlus/Drawing/Theme/ExcelThemeLine.cs index 843488b07e..8fa764b019 100644 --- a/src/EPPlus/Drawing/Theme/ExcelThemeLine.cs +++ b/src/EPPlus/Drawing/Theme/ExcelThemeLine.cs @@ -69,7 +69,7 @@ public eLineCap Cap /// /// The compound line type to be used for the underline stroke /// - public eCompundLineStyle CompoundLineStyle + public eCompoundLineStyle CompoundLineStyle { get { diff --git a/src/EPPlus/Drawing/Theme/ExcelThemeLineStyles.cs b/src/EPPlus/Drawing/Theme/ExcelThemeLineStyles.cs index 149332f8ac..2a4473ce37 100644 --- a/src/EPPlus/Drawing/Theme/ExcelThemeLineStyles.cs +++ b/src/EPPlus/Drawing/Theme/ExcelThemeLineStyles.cs @@ -28,7 +28,7 @@ public class ExcelThemeLineStyles : XmlHelper, IEnumerable internal ExcelThemeLineStyles(XmlNamespaceManager nameSpaceManager, XmlNode topNode) : base(nameSpaceManager, topNode) { _list = new List(); - foreach (XmlNode node in topNode.ChildNodes) + foreach (XmlElement node in topNode.ChildNodes) { _list.Add(new ExcelThemeLine(nameSpaceManager, node)); } diff --git a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs index 9ae1dcf246..8c697223a4 100644 --- a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs +++ b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs @@ -86,7 +86,7 @@ internal string Anchor /// Gets a style from the semi-colo separated list with the specific key /// /// The list - /// The key to search for + /// The _key to search for /// The value to return /// True if found protected bool GetStyle(string style, string key, out string value) @@ -116,7 +116,7 @@ protected bool GetStyle(string style, string key, out string value) /// Sets the style in a semicolon separated list /// /// The list - /// The key + /// The _key /// The value /// The new list internal protected string SetStyle(string style, string key, string value) diff --git a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingFill.cs b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingFill.cs index d2ab96c9f9..ce8524f078 100644 --- a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingFill.cs +++ b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingFill.cs @@ -125,7 +125,7 @@ public ExcelVmlDrawingGradientFill GradientSettings } internal ExcelVmlDrawingPictureFill _patternPictureSettings = null; /// - /// Image and pattern specific settings used when is set to Pattern, Tile or Frame. + /// BulletImage and pattern specific settings used when is set to Pattern, Tile or Frame. /// public ExcelVmlDrawingPictureFill PatternPictureSettings { diff --git a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPicture.cs b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPicture.cs index 1902d5b7eb..78f1ef32ca 100644 --- a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPicture.cs +++ b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPicture.cs @@ -114,7 +114,7 @@ public string Title } ExcelImage _image; /// - /// The Image + /// The BulletImage /// public ExcelImage Image { @@ -354,24 +354,7 @@ IPictureRelationDocument RelationDocument void IPictureContainer.RemoveImage() { - IPictureContainer container = this; - var relDoc = container.RelationDocument; - if (relDoc.Hashes.TryGetValue(container.ImageHash, out HashInfo hi)) - { - if (hi.RefCount <= 1) - { - relDoc.Package.PictureStore.RemoveImage(container.ImageHash, this); - if (container.RelPic != null) - { - relDoc.RelatedPart.DeleteRelationship(container.RelPic.Id); - } - relDoc.Hashes.Remove(container.ImageHash); - } - else - { - hi.RefCount--; - } - } + PictureStore.RemoveImage(this); } void IPictureContainer.SetNewImage() diff --git a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureCollection.cs b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureCollection.cs index 8d752876f5..28d0d3776e 100644 --- a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureCollection.cs +++ b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureCollection.cs @@ -109,7 +109,7 @@ public void Remove(ExcelVmlDrawingPicture item) /// Indexer /// /// Index - /// The VML Drawing Picture object + /// The VML Drawing Blip object public ExcelVmlDrawingPicture this[int Index] { get diff --git a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureFill.cs b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureFill.cs index b600e6bb6c..3c9e3e6316 100644 --- a/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureFill.cs +++ b/src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureFill.cs @@ -64,7 +64,7 @@ public eVmlAspectRatio AspectRatio } } /// - /// A string representing the pictures Size. + /// A string representing the pictures FontSize. /// For Example: 0,0 /// public string Size diff --git a/src/EPPlus/Drawing/Vml/enum/eVmlAspectRatio.cs b/src/EPPlus/Drawing/Vml/enum/eVmlAspectRatio.cs index 8c828f776e..9875b352ff 100644 --- a/src/EPPlus/Drawing/Vml/enum/eVmlAspectRatio.cs +++ b/src/EPPlus/Drawing/Vml/enum/eVmlAspectRatio.cs @@ -10,11 +10,11 @@ public enum eVmlAspectRatio /// Ignore, /// - /// Image is at least as big as Size. + /// BulletImage is at least as big as FontSize. /// AtLeast, /// - /// Image is no bigger than Size. + /// BulletImage is no bigger than FontSize. /// AtMost } diff --git a/src/EPPlus/Drawing/Vml/enum/eVmlFillType.cs b/src/EPPlus/Drawing/Vml/enum/eVmlFillType.cs index 7a0f1e4182..7637bfbb69 100644 --- a/src/EPPlus/Drawing/Vml/enum/eVmlFillType.cs +++ b/src/EPPlus/Drawing/Vml/enum/eVmlFillType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Drawing.Vml { /// - /// Type of fill style for a vml drawing. + /// BulletType of fill style for a vml drawing. /// public enum eVmlFillType { diff --git a/src/EPPlus/EPPlus.csproj b/src/EPPlus/EPPlus.csproj index 01a63f80f3..6fe3f55ef0 100644 --- a/src/EPPlus/EPPlus.csproj +++ b/src/EPPlus/EPPlus.csproj @@ -1,10 +1,12 @@  - net8.0;net9.0;net10.0;netstandard2.1;netstandard2.0;net462;net35 + net8.0;net9.0;net10.0;netstandard2.1;netstandard2.0;net462 8.6.1.0 8.6.1.0 8.6.1 true + + $(TargetsForTfmSpecificBuildOutput);IncludeReferencedProjectsInPackage https://epplussoftware.com EPPlus Software AB license.md @@ -35,7 +37,7 @@ * New functions: * GROUPBY, PIVOTBY, TRIMRANGE, WRAPROWS, WRAPCOLS, USDOLLAR, CODE, ENCODEURL, ISFORMULA * Support for [Trim reference operator](https://github.com/EPPlusSoftware/EPPlus/wiki/Trim-reference-operator). - * Minor bug fixes. + * Minor bug fixes. ## Version 8.5.4 * Minor bug fixes. @@ -723,27 +725,51 @@ EPPlusLogo.png - + + + + + + + - + + + + + + + + bin\$(Configuration)\$(TargetFramework)\EPPlus.xml + + + @@ -773,7 +799,7 @@ - + @@ -802,6 +828,7 @@ + @@ -819,7 +846,7 @@ - Never + Never @@ -847,10 +874,10 @@ Never - PreserveNewest + PreserveNewest PreserveNewest - + \ No newline at end of file diff --git a/src/EPPlus/Encryption/EncryptionHandler.cs b/src/EPPlus/Encryption/EncryptionHandler.cs index a176696dd7..ce739bcbab 100644 --- a/src/EPPlus/Encryption/EncryptionHandler.cs +++ b/src/EPPlus/Encryption/EncryptionHandler.cs @@ -141,7 +141,7 @@ private MemoryStream EncryptPackageAgile(byte[] package, ExcelEncryption encrypt encr.KeyValue = new byte[encr.KeyBits / 8]; rnd.GetBytes(encr.KeyValue); - //Get the password key. + //Get the password _key. var hashProvider = GetHashProvider(encryptionInfo.KeyEncryptors[0]); var baseHash = GetPasswordHashSpinPrepending(hashProvider, encr.SaltValue, encryption.Password, encr.SpinCount, encr.HashSize); var hashFinal = GetFinalHash(hashProvider, BlockKey_KeyValue, baseHash); @@ -430,7 +430,7 @@ private byte[] CreateTransformInfoPrimary() /// /// The password /// - /// The Encryption key + /// The Encryption _key /// private EncryptionInfoBinary CreateEncryptionInfo(string password, AlgorithmID algID, out byte[] key) { @@ -594,7 +594,7 @@ private MemoryStream DecryptAgile(EncryptionInfoAgile encryptionInfo, string pas var baseHash = GetPasswordHashSpinPrepending(hashProvider, encr.SaltValue, password, encr.SpinCount, encr.HashSize); - //Get the keys for the verifiers and the key value + //Get the keys for the verifiers and the _key value var valInputKey = GetFinalHash(hashProvider, BlockKey_HashInput, baseHash); var valHashKey = GetFinalHash(hashProvider, BlockKey_HashValue, baseHash); var valKeySizeKey = GetFinalHash(hashProvider, BlockKey_KeyValue, baseHash); @@ -681,8 +681,8 @@ private HashAlgorithm GetHashProvider(EncryptionInfoAgile.EncryptionKeyData encr { case eHashAlgorithm.MD5: return new MD5CryptoServiceProvider(); - case eHashAlgorithm.RIPEMD160: - return new RIPEMD160Managed(); + //case eHashAlgorithm.RIPEMD160: + // return new RIPEMD160Managed(); case eHashAlgorithm.SHA1: return new SHA1CryptoServiceProvider(); case eHashAlgorithm.SHA256: @@ -745,7 +745,7 @@ private MemoryStream DecryptBinary(EncryptionInfoBinary encryptionInfo, string p /// /// Validate the password /// - /// The encryption key + /// The encryption _key /// The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document /// private bool IsPasswordValid(byte[] key, EncryptionInfoBinary encryptionInfo) @@ -984,7 +984,7 @@ private byte[] GetPasswordHashBinary(string password, EncryptionInfoBinary encry Array.Copy(System.BitConverter.GetBytes(0), 0, tempHash, hash.Length, 4); hash = hashProvider.ComputeHash(tempHash); - /***** Now use the derived key algorithm *****/ + /***** Now use the derived _key algorithm *****/ byte[] derivedKey = new byte[64]; int keySizeBytes = encryptionInfo.Header.KeySize / 8; @@ -995,7 +995,7 @@ private byte[] GetPasswordHashBinary(string password, EncryptionInfoBinary encry byte[] X1 = hashProvider.ComputeHash(derivedKey); - //if verifier size is bigger than the key size we can return X1 + //if verifier size is bigger than the _key size we can return X1 if ((int)encryptionInfo.Verifier.VerifierHashSize > keySizeBytes) return FixHashSize(X1, keySizeBytes); @@ -1026,7 +1026,7 @@ private byte[] GetPasswordHashBinary(string password, EncryptionInfoBinary encry /// /// The password /// The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document - /// The block key appended to the hash to obtain the final hash + /// The block _key appended to the hash to obtain the final hash /// The hash to encrypt the document private byte[] GetPasswordHashAgile(string password, EncryptionInfoAgile.EncryptionKeyEncryptor encr, byte[] blockKey) { diff --git a/src/EPPlus/Enums.cs b/src/EPPlus/Enums.cs index c596fa3de1..82823e88f2 100644 --- a/src/EPPlus/Enums.cs +++ b/src/EPPlus/Enums.cs @@ -112,7 +112,7 @@ internal enum eProtectedRangeAlgorithm public enum CompressionLevel { /// - /// Level 0, no compression + /// IndentLevel 0, no compression /// Level0 = 0, /// @@ -120,7 +120,7 @@ public enum CompressionLevel /// None = 0, /// - /// Level 1, Best speed + /// IndentLevel 1, Best speed /// Level1 = 1, /// @@ -128,43 +128,43 @@ public enum CompressionLevel /// BestSpeed = 1, /// - /// Level 2 + /// IndentLevel 2 /// Level2 = 2, /// - /// Level 3 + /// IndentLevel 3 /// Level3 = 3, /// - /// Level 4 + /// IndentLevel 4 /// Level4 = 4, /// - /// Level 5 + /// IndentLevel 5 /// Level5 = 5, /// - /// Level 6 + /// IndentLevel 6 /// Level6 = 6, /// - /// Default, Level 6 + /// Default, IndentLevel 6 /// Default = 6, /// - /// Level 7 + /// IndentLevel 7 /// Level7 = 7, /// - /// Level 8 + /// IndentLevel 8 /// Level8 = 8, /// - /// Level 9 + /// IndentLevel 9 /// BestCompression = 9, /// - /// Best compression, Level 9 + /// Best compression, IndentLevel 9 /// Level9 = 9, } diff --git a/src/EPPlus/ExcelCellBase.cs b/src/EPPlus/ExcelCellBase.cs index ec0e926fd4..80c8d03530 100644 --- a/src/EPPlus/ExcelCellBase.cs +++ b/src/EPPlus/ExcelCellBase.cs @@ -781,6 +781,7 @@ public static bool IsValidAddress(string address) return false; } + if (IsValidRangeAddress(address)==false) //TODO: update IsValidRangeAddress to use tokens instead; { return IsValidTableAddress(address); diff --git a/src/EPPlus/ExcelConfigurationReader.cs b/src/EPPlus/ExcelConfigurationReader.cs index 10a343cc52..9e11e42103 100644 --- a/src/EPPlus/ExcelConfigurationReader.cs +++ b/src/EPPlus/ExcelConfigurationReader.cs @@ -29,7 +29,7 @@ internal static class ExcelConfigurationReader /// /// Reads an environment variable from the o/s. If an error occors it will rethrow the unless SuppressInitializationExceptions of the is set to true. /// - /// The key of the requested variable + /// The _key of the requested variable /// The /// Configuration of the package /// A list of logged objects. diff --git a/src/EPPlus/ExcelHeaderFooter.cs b/src/EPPlus/ExcelHeaderFooter.cs index 8da37d5dae..c5e349a7a8 100644 --- a/src/EPPlus/ExcelHeaderFooter.cs +++ b/src/EPPlus/ExcelHeaderFooter.cs @@ -208,7 +208,7 @@ public string RightAlignedText /// /// Inserts a picture at the end of the text in the header or footer /// - /// The image object containing the Picture + /// The image object containing the Blip /// Alignment. The image object will be inserted at the end of the Text. public ExcelVmlDrawingPicture InsertPicture(FileInfo PictureFile, PictureAlignment Alignment) { diff --git a/src/EPPlus/ExcelNamedRangeCollection.cs b/src/EPPlus/ExcelNamedRangeCollection.cs index 9782ed35b8..9665a4e461 100644 --- a/src/EPPlus/ExcelNamedRangeCollection.cs +++ b/src/EPPlus/ExcelNamedRangeCollection.cs @@ -299,10 +299,10 @@ public void Remove(string Name) } } /// - /// Checks collection for the presence of a key + /// Checks collection for the presence of a _key /// - /// key to search for - /// true if the key is in the collection + /// _key to search for + /// true if the _key is in the collection public bool ContainsKey(string key) { return _dic.ContainsKey(key); @@ -320,10 +320,10 @@ public int Count /// /// Name indexer /// - /// The name (key) for a Named range + /// The name (_key) for a Named range /// a reference to the range /// - /// Throws a KeyNotFoundException if the key is not in the collection. + /// Throws a KeyNotFoundException if the _key is not in the collection. /// public ExcelNamedRange this[string Name] { diff --git a/src/EPPlus/ExcelPackage.cs b/src/EPPlus/ExcelPackage.cs index 6aec485c67..80f42f9be9 100644 --- a/src/EPPlus/ExcelPackage.cs +++ b/src/EPPlus/ExcelPackage.cs @@ -25,7 +25,6 @@ Date Author Change using OfficeOpenXml.Configuration; using OfficeOpenXml.EventArguments; using OfficeOpenXml.Utils.FileUtils; - #if (!NET35) using OfficeOpenXml.SensitivityLabels; #endif @@ -81,14 +80,14 @@ namespace OfficeOpenXml /// //Ok now format the values; /// using (var range = worksheet.Cells[1, 1, 1, 5]) /// { - /// range.Style.Font.Bold = true; + /// range.Style.Font.FontBold = true; /// range.Style.Fill.PatternType = ExcelFillStyle.Solid; /// range.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue); /// range.Style.Font.Color.SetColor(Color.White); /// } /// /// worksheet.Cells["A5:E5"].Style.Border.Top.Style = ExcelBorderStyle.Thin; - /// worksheet.Cells["A5:E5"].Style.Font.Bold = true; + /// worksheet.Cells["A5:E5"].Style.Font.FontBold = true; /// /// worksheet.Cells[5, 3, 5, 5].Formula = string.Format("SUBTOTAL(9,{0})", new ExcelAddress(2,3,4,3).Address); /// worksheet.Cells["C2:C5"].Style.Numberformat.Format = "#,##0"; @@ -100,7 +99,7 @@ namespace OfficeOpenXml /// worksheet.Cells["A1:E5"].AutoFitColumns(0); /// /// // lets set the header text - /// worksheet.HeaderFooter.oddHeader.CenteredText = "&24&U&\"Arial,Regular Bold\" Inventory"; + /// worksheet.HeaderFooter.oddHeader.CenteredText = "&24&U&\"Arial,Regular FontBold\" Inventory"; /// // add the page number to the footer plus the total number of pages /// worksheet.HeaderFooter.oddFooter.RightAlignedText = /// string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages); @@ -782,7 +781,7 @@ public ExcelWorkbook Workbook { if (License.IsLicenseSet(_initErrors) == false) { - throw (new LicenseNotSetException("Please set the license using one of the methods on the static property ExcelPackage.License. See https://epplussoftware.com/developers/licensenotsetexception for more information")); + throw (new LicenseNotSetException("Please set the license using one of the methods on the static properszty ExcelPackage.License. See https://epplussoftware.com/developers/licensenotsetexception for more information")); } var nsm = CreateDefaultNSM(); @@ -970,7 +969,7 @@ public void Save() { //Close any open memory stream and "renew" them. This can occure if the package is saved twice. //The stream is left open on save to enable the user to read the stream-property. - //Non-memorystream streams will leave the closing to the user before saving a second time. + //Non-MemoryStream streams will leave the closing to the user before saving a second time. CloseStream(); } @@ -1225,14 +1224,21 @@ public CompatibilitySettings Compatibility return _compatibility; } } + ExcelPackageSettings _settings=null; /// /// Package generic settings /// public ExcelPackageSettings Settings { - get; - private set; - } = new ExcelPackageSettings(); + get + { + if(_settings==null) + { + _settings = new ExcelPackageSettings(this); + } + return _settings; + } + } #if !NET35 static MemorySettings _memorySettings = null; /// diff --git a/src/EPPlus/ExcelPackageSettings.cs b/src/EPPlus/ExcelPackageSettings.cs index ea7fa6369a..40022a6410 100644 --- a/src/EPPlus/ExcelPackageSettings.cs +++ b/src/EPPlus/ExcelPackageSettings.cs @@ -31,9 +31,10 @@ public static Dictionary> CultureSpecificBuildIn get; } = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - internal ExcelPackageSettings() + ExcelPackage _package; + internal ExcelPackageSettings(ExcelPackage package) { - + _package = package; } /// /// Do not call garbage collection when ExcelPackage is disposed. @@ -50,7 +51,7 @@ public ExcelTextSettings TextSettings { if (_textSettings == null) { - _textSettings = new ExcelTextSettings(); + _textSettings = new ExcelTextSettings(_package); } return _textSettings; } diff --git a/src/EPPlus/ExcelProtectedRangeCollection.cs b/src/EPPlus/ExcelProtectedRangeCollection.cs index 264e35d89d..a56813605a 100644 --- a/src/EPPlus/ExcelProtectedRangeCollection.cs +++ b/src/EPPlus/ExcelProtectedRangeCollection.cs @@ -41,7 +41,7 @@ internal ExcelProtectedRangeCollection(ExcelWorksheet ws) _collectionNode = (XmlElement)GetNode(_collectionNodePath); if(_collectionNode!=null) { - foreach (XmlNode node in _collectionNode.ChildNodes) + foreach (XmlElement node in _collectionNode.ChildNodes) { _list.Add(new ExcelProtectedRange(ws.NameSpaceManager, node)); } diff --git a/src/EPPlus/ExcelRangeBase.cs b/src/EPPlus/ExcelRangeBase.cs index 0f5b44f007..d11c845020 100644 --- a/src/EPPlus/ExcelRangeBase.cs +++ b/src/EPPlus/ExcelRangeBase.cs @@ -19,6 +19,7 @@ Date Author Change using OfficeOpenXml.Export.HtmlExport.Interfaces; using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.Excel.Functions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.Sorting; using OfficeOpenXml.Style; @@ -48,8 +49,6 @@ public partial class ExcelRangeBase : ExcelAddress, IExcelCell, IDisposable, IEn private delegate void _setValue(ExcelRangeBase range, object value, int row, int col); private _changeProp _changePropMethod; private int _styleID; - private static SourceCodeTokenizer _tokenizer = new SourceCodeTokenizer(null, null, false, true); - private FunctionRepository _functions; private readonly ExcelRangePicture _rangePicture; #region Constructors internal ExcelRangeBase(ExcelWorksheet xlWorksheet) @@ -59,7 +58,6 @@ internal ExcelRangeBase(ExcelWorksheet xlWorksheet) _workbook = _worksheet.Workbook; _rangePicture = new ExcelRangePicture(this); SetDelegate(); - _functions = _workbook.FormulaParser.ParsingContext.Configuration.FunctionRepository; } internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) : @@ -71,7 +69,6 @@ internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) : base.SetRCFromTable(_worksheet._package, null); if (string.IsNullOrEmpty(_ws)) _ws = _worksheet == null ? "" : _worksheet.Name; SetDelegate(); - _functions = _workbook.FormulaParser.ParsingContext.Configuration.FunctionRepository; } internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) @@ -85,7 +82,6 @@ internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string add } if (string.IsNullOrEmpty(_ws)) _ws = (xlWorksheet == null ? null : xlWorksheet.Name); SetDelegate(); - _functions = _workbook.FormulaParser.ParsingContext.Configuration.FunctionRepository; } #endregion private void Init(ExcelWorksheet xlWorksheet) @@ -872,7 +868,24 @@ public string Text } } } - + /// + /// Returns the Text for a merged cell. + /// + internal string TextMerged + { + get + { + if(Merge) + { + var ma = _worksheet.MergedCells[_fromRow, _fromCol]; + if(ma!=null) + { + return _worksheet.Cells[ma].Text; + } + } + return Text; + } + } /// /// Used to add/remove cell pictures in the range /// @@ -925,6 +938,7 @@ public void AutoFitColumns(double MinimumWidth, double MaximumWidth) af.AutofitColumn(MinimumWidth, MaximumWidth); #endif } + internal string TextForWidth { get @@ -2291,7 +2305,7 @@ public void CreateArrayFormula(string ArrayFormula, bool isDynamic = false) { //Array formulas are only allowed in tables as CalculatedColumn formula //Or single-cell. Excel does not allow multi-cell array formulas in tables. - if (Start.Address != End.Address) + if(Start.Address != End.Address) { throw (new InvalidOperationException("Multi-Cell array formulas are not allowed in tables.")); } diff --git a/src/EPPlus/ExcelRangeBase_Fill.cs b/src/EPPlus/ExcelRangeBase_Fill.cs index 4a32721aa6..91cbc4bcab 100644 --- a/src/EPPlus/ExcelRangeBase_Fill.cs +++ b/src/EPPlus/ExcelRangeBase_Fill.cs @@ -160,7 +160,7 @@ public void FillDateTime(Action options) /// /// Fills the range columnwise (Down) using the values in the list. /// - /// Type used in the list. + /// BulletType used in the list. /// The list to use. public void FillList(IEnumerable list) { diff --git a/src/EPPlus/ExcelRangeBase_Load.cs b/src/EPPlus/ExcelRangeBase_Load.cs index edcfadbe36..86062f0ef6 100644 --- a/src/EPPlus/ExcelRangeBase_Load.cs +++ b/src/EPPlus/ExcelRangeBase_Load.cs @@ -884,7 +884,7 @@ public ExcelRangeBase LoadFromDictionaries(IEnumerable /// A list of dictionaries/> - /// If true the key names from the first instance will be used as headers + /// If true the _key names from the first instance will be used as headers /// The filled range /// /// @@ -918,7 +918,7 @@ public ExcelRangeBase LoadFromDictionaries(IEnumerable /// A list of dictionaries/> - /// If true the key names from the first instance will be used as headers + /// If true the _key names from the first instance will be used as headers /// Will create a table with this style. If set to TableStyles.None no table will be created /// The filled range /// @@ -953,7 +953,7 @@ public ExcelRangeBase LoadFromDictionaries(IEnumerable /// A list of dictionaries - /// If true the key names from the first instance will be used as headers + /// If true the _key names from the first instance will be used as headers /// Will create a table with this style. If set to TableStyles.None no table will be created /// Keys that should be used, keys omitted will not be included /// The filled range @@ -999,7 +999,7 @@ public ExcelRangeBase LoadFromDictionaries(IEnumerable /// A list of dictionaries - /// If true the key names from the first instance will be used as headers + /// If true the _key names from the first instance will be used as headers /// Will create a table with this style. If set to TableStyles.None no table will be created /// Keys that should be used, keys omitted will not be included /// The filled range diff --git a/src/EPPlus/ExcelRangeColumn.cs b/src/EPPlus/ExcelRangeColumn.cs index 7d4ccca8f1..1d30e4ad53 100644 --- a/src/EPPlus/ExcelRangeColumn.cs +++ b/src/EPPlus/ExcelRangeColumn.cs @@ -72,12 +72,12 @@ bool PageBreak /// void UnGroup(); /// - /// Collapses and hides the column's children. Children are columns immegetaly to the right or left of the column depending on the + /// Collapses and hides the column's children. ChartAreaRenderItems are columns immegetaly to the right or left of the column depending on the /// If true, all children will be collapsed and hidden. If false, only the children of the referenced columns are collapsed. /// void CollapseChildren(bool allLevels = true); /// - /// Expands and shows the column's children. Children are columns immegetaly to the right or left of the column depending on the + /// Expands and shows the column's children. ChartAreaRenderItems are columns immegetaly to the right or left of the column depending on the /// If true, all children will be expanded and shown. If false, only the children of the referenced columns will be expanded. /// void ExpandChildren(bool allLevels = true); @@ -152,7 +152,7 @@ public void UnGroup() } /// - /// Collapses and hides the column's children. Children are columns immegetaly to the right or left of the column depending on the + /// Collapses and hides the column's children. ChartAreaRenderItems are columns immegetaly to the right or left of the column depending on the /// If true, all children will be collapsed and hidden. If false, only the children of the referenced columns are collapsed. /// public void CollapseChildren(bool allLevels = true) @@ -174,7 +174,7 @@ public void CollapseChildren(bool allLevels = true) } } /// - /// Expands and shows the column's children. Children are columns immegetaly to the right or left of the column depending on the + /// Expands and shows the column's children. ChartAreaRenderItems are columns immegetaly to the right or left of the column depending on the /// If true, all children will be expanded and shown. If false, only the children of the referenced columns will be expanded. /// public void ExpandChildren(bool allLevels = true) diff --git a/src/EPPlus/ExcelRangeRow.cs b/src/EPPlus/ExcelRangeRow.cs index f5a993c5a3..4cc1d8c012 100644 --- a/src/EPPlus/ExcelRangeRow.cs +++ b/src/EPPlus/ExcelRangeRow.cs @@ -70,12 +70,12 @@ bool CustomHeight /// void Ungroup(); /// - /// Collapses and hides the rows's children. Children are rows immegetaly below or top of the row depending on the + /// Collapses and hides the rows's children. ChartAreaRenderItems are rows immegetaly below or top of the row depending on the /// If true, all children will be collapsed and hidden. If false, only the children of the referenced rows are collapsed. /// void CollapseChildren(bool allLevels = true); /// - /// Expands and shows the rows's children. Children are columns immegetaly below or top of the row depending on the + /// Expands and shows the rows's children. ChartAreaRenderItems are columns immegetaly below or top of the row depending on the /// If true, all children will be expanded and shown. If false, only the children of the referenced columns will be expanded. /// void ExpandChildren(bool allLevels = true); @@ -473,7 +473,7 @@ public void Ungroup() SetValue(new Action((x, v) => { if (x.OutlineLevel >= 0) x.OutlineLevel += (short)v; }), -1); } /// - /// Collapses and hides the rows's children. Children are rows immegetaly below or top of the row depending on the + /// Collapses and hides the rows's children. ChartAreaRenderItems are rows immegetaly below or top of the row depending on the /// If true, all children will be collapsed and hidden. If false, only the children of the referenced rows are collapsed. /// public void CollapseChildren(bool allLevels = true) @@ -495,7 +495,7 @@ public void CollapseChildren(bool allLevels = true) } } /// - /// Expands and shows the rows's children. Children are columns immegetaly below or top of the row depending on the + /// Expands and shows the rows's children. ChartAreaRenderItems are columns immegetaly below or top of the row depending on the /// If true, all children will be expanded and shown. If false, only the children of the referenced columns will be expanded. /// public void ExpandChildren(bool allLevels = true) diff --git a/src/EPPlus/ExcelStyleCollection.cs b/src/EPPlus/ExcelStyleCollection.cs index 64d1a2d317..21d203e680 100644 --- a/src/EPPlus/ExcelStyleCollection.cs +++ b/src/EPPlus/ExcelStyleCollection.cs @@ -118,9 +118,9 @@ internal int Add(string key, T item) return _list.Count-1; } /// - /// Finds the key + /// Finds the _key /// - /// the key to be found + /// the _key to be found /// The found object. /// True if found internal bool FindById(string key, ref T obj) diff --git a/src/EPPlus/ExcelTextSettings.cs b/src/EPPlus/ExcelTextSettings.cs index 52fa9a222d..e742497d8d 100644 --- a/src/EPPlus/ExcelTextSettings.cs +++ b/src/EPPlus/ExcelTextSettings.cs @@ -14,6 +14,7 @@ Date Author Change using OfficeOpenXml.Core.Worksheet.Fonts.GenericFontMetrics; using OfficeOpenXml.Interfaces.Drawing.Text; using System; +using EPPlus.Fonts.OpenType; namespace OfficeOpenXml { @@ -22,10 +23,12 @@ namespace OfficeOpenXml /// public class ExcelTextSettings { - internal ExcelTextSettings() + ExcelPackage _package; + internal ExcelTextSettings(ExcelPackage package = null) { PrimaryTextMeasurer = new GenericFontMetricsTextMeasurer(); AutofitScaleFactor = 1f; + _package = package; } ITextMeasurer _primaryTextMeasurer = null; ITextMeasurer _fallbackTextMeasurer = null; @@ -82,7 +85,6 @@ public ITextMeasurer GenericTextMeasurer return new GenericFontMetricsTextMeasurer(); } } - /// /// Measures a text with default settings when there is no other option left... /// diff --git a/src/EPPlus/ExcelWorkbook.cs b/src/EPPlus/ExcelWorkbook.cs index 282f47ff65..6157d386d6 100644 --- a/src/EPPlus/ExcelWorkbook.cs +++ b/src/EPPlus/ExcelWorkbook.cs @@ -10,42 +10,45 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Xml; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Globalization; -using System.Linq; -using OfficeOpenXml.VBA; -using OfficeOpenXml.FormulaParsing; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using OfficeOpenXml.Packaging.Ionic.Zip; -using OfficeOpenXml.Drawing.Theme; +using EPPlus.DrawingRenderer; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.CellPictures; using OfficeOpenXml.Compatibility; +using OfficeOpenXml.Constants; using OfficeOpenXml.Core.CellStore; -using OfficeOpenXml.Drawing.Slicer; -using OfficeOpenXml.ThreadedComments; -using OfficeOpenXml.Table; -using OfficeOpenXml.Table.PivotTable; +using OfficeOpenXml.Data.Connection; +using OfficeOpenXml.Data.CustomXml; +using OfficeOpenXml.DigitalSignatures; using OfficeOpenXml.Drawing; -using OfficeOpenXml.Constants; -using OfficeOpenXml.ExternalReferences; -using OfficeOpenXml.Packaging; -using OfficeOpenXml.Export.HtmlExport.Interfaces; +using OfficeOpenXml.Drawing.Slicer; +using OfficeOpenXml.Drawing.Theme; using OfficeOpenXml.Export.HtmlExport.Exporters; +using OfficeOpenXml.Export.HtmlExport.Interfaces; +using OfficeOpenXml.ExternalReferences; +using OfficeOpenXml.FormulaParsing; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; +using OfficeOpenXml.Interfaces.Fonts; using OfficeOpenXml.Metadata; +using OfficeOpenXml.Packaging; +using OfficeOpenXml.Packaging.Ionic.Zip; using OfficeOpenXml.RichData; -using OfficeOpenXml.Style; -using OfficeOpenXml.CellPictures; using OfficeOpenXml.RichData.IndexRelations; -using OfficeOpenXml.DigitalSignatures; -using OfficeOpenXml.Utils.XML; -using OfficeOpenXml.Utils.TypeConversion; -using OfficeOpenXml.Utils.FileUtils; +using OfficeOpenXml.Style; +using OfficeOpenXml.Table; +using OfficeOpenXml.Table.PivotTable; +using OfficeOpenXml.ThreadedComments; using OfficeOpenXml.Utils.EnumUtils; -using OfficeOpenXml.Data.CustomXml; -using OfficeOpenXml.Data.Connection; +using OfficeOpenXml.Utils.FileUtils; +using OfficeOpenXml.Utils.TypeConversion; +using OfficeOpenXml.Utils.XML; +using OfficeOpenXml.VBA; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; namespace OfficeOpenXml { @@ -1456,6 +1459,64 @@ public int? DefaultThemeVersion } } } + + RenderContext _renderContext = null; + + /// + /// Rendering-wide resources for this workbook (font engine, etc.), flowed down the drawing + /// render stack. Created lazily with a default font engine if none has been configured. + /// Internal: callers configure fonts via rather than touching + /// this directly. + /// + internal RenderContext RenderContext + { + get + { + if (_renderContext == null) + { + _renderContext = new RenderContext(() => new OpenTypeFontEngine()); + } + return _renderContext; + } + set + { + _renderContext = value; + } + } + + /// + /// Configures the fonts used when rendering drawings (charts, shapes) from this workbook to + /// image formats such as SVG. Use this to add font directories, control whether system font + /// directories are searched, or register fallback chains. + /// + /// A callback that configures the font settings for this workbook. + /// + /// The configuration is applied when this workbook first renders a drawing. Call this before + /// rendering. The font engine is per workbook configuring one workbook does not affect any + /// other workbook or any global state. + /// + public void ConfigureFonts(Action configure) + { + if (configure == null) + throw new ArgumentNullException("configure"); + + RenderContext = new RenderContext(() => new OpenTypeFontEngine(configure)); + } + + /// + /// Supplies a pre-built font engine for this workbook's rendering. Intended for advanced + /// scenarios and testing where a specific engine instance must be used. Per workbook never + /// global. + /// + /// The font engine to use for this workbook. + internal void UseFontEngine(OpenTypeFontEngine engine) + { + if (engine == null) + throw new ArgumentNullException("engine"); + + RenderContext = new RenderContext(() => engine); + } + bool _fullPrecision; /// /// If false, EPPlus will round cell values to the number of decimals as displayed in the cell by using the cells number format when calculating the workbook. @@ -2214,6 +2275,11 @@ public void Dispose() _formulaParser.Dispose(); _formulaParser = null; } + if (_renderContext != null) + { + _renderContext.Dispose(); + _renderContext = null; + } } /// diff --git a/src/EPPlus/ExcelWorksheet.cs b/src/EPPlus/ExcelWorksheet.cs index dd507d8bd9..e4543bcc19 100644 --- a/src/EPPlus/ExcelWorksheet.cs +++ b/src/EPPlus/ExcelWorksheet.cs @@ -23,16 +23,10 @@ Date Author Change using OfficeOpenXml.Data.QueryTable; using OfficeOpenXml.DataValidation; using OfficeOpenXml.Drawing; -using OfficeOpenXml.Drawing.Chart; -using OfficeOpenXml.Drawing.Controls; using OfficeOpenXml.Drawing.Interfaces; -using OfficeOpenXml.Drawing.OleObject; -using OfficeOpenXml.Drawing.Slicer; using OfficeOpenXml.Drawing.Vml; using OfficeOpenXml.Filter; using OfficeOpenXml.FormulaParsing; -using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; -using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.Packaging; using OfficeOpenXml.Packaging.Ionic.Zip; @@ -1980,7 +1974,7 @@ private void SetValueFromXml(XmlReader xr, string type, int styleID, int row, in /// &UUnderlined /// &EDouble Underline /// &K:xxxxxxColor. ex &K:FF0000 for red - /// &"Font,Regular Bold Italic"Changes the font. Regular or Bold or Italic or Bold Italic can be used. ex &"Arial,Bold Italic" + /// &"Font,Regular FontBold FontItalic"Changes the font. Regular or FontBold or FontItalic or FontBold FontItalic can be used. ex &"Arial,FontBold FontItalic" /// &nnChange font size. nn is an integer. ex &24 /// &GPlaceholder for images. Images cannot be added by the library, but its possible to use in a template. /// @@ -2557,6 +2551,10 @@ internal void Save(bool hasLoadedPivotTables) } } + private void SaveDrawings(bool hasLoadedPivotTables) + { + Drawings.SaveDrawings(hasLoadedPivotTables); + } private void SaveSlicers() { SlicerXmlSources.Save(); @@ -2893,7 +2891,8 @@ private void EnsureIgnorablesAreCorrect() if (string.IsNullOrEmpty(existingIgnorables) == false) { var namespaces = existingIgnorables.Split(' '); - if (!namespaces.Any(x => x == "xr")) + //var ignorablesConcatenated = string.Concat(namespaces); + if (namespaces.Any(x => x == "xr") == false) { WorksheetXml.DocumentElement.SetAttribute("Ignorable", ExcelPackage.schemaMarkupCompatibility, existingIgnorables + " xr"); } @@ -2997,6 +2996,20 @@ public ExcelRangeBase Dimension } } } + + /// + /// Dimension address for the worksheet for cells that has a visible difference from default cells. + /// Top left cell to Bottom right. + /// If the worksheet has no cells, null is returned + /// + public ExcelRangeBase DimensionByVisibility + { + get + { + return GetDimension(true); + } + } + /// /// Dimension address for the worksheet for cells with a value different than null. /// Top left cell to Bottom right. @@ -3006,57 +3019,152 @@ public ExcelRangeBase DimensionByValue { get { - CheckSheetTypeAndNotDisposed(); - if (_values.GetDimension(out int fr, out int fc, out int tr, out int tc)) + return GetDimension(false); + } + } + + + private ExcelRangeBase GetDimension(bool byVisibility) + { + CheckSheetTypeAndNotDisposed(); + if (_values.GetDimension(out int fr, out int fc, out int tr, out int tc)) + { + var fvc = FirstValueCell; + var lvc = LastValueCell; + // Row range comes from values only — styling never extends the height. + var fromRow = fvc._fromRow; + var toRow = lvc._toRow; + + // For a single value cell, the value-based dimension is just that cell, + // but visible styling on other columns within the same row may still + // extend the column range, so we keep going rather than early-returning + // when byVisibility is requested. + if (byVisibility == false && fvc.Address == lvc.Address) { - var fvc = FirstValueCell; - var lvc = LastValueCell; - if (fvc.Address == lvc.Address) return Cells[fvc.Address]; - var fromRow = fvc._fromRow; - var toRow = lvc._toRow; - int fromCol, toCol; + return Cells[fvc.Address]; + } - if (fvc._fromCol == fc) - { - fromCol = fvc._fromCol; - } - else + int fromCol, toCol; + + // ---- Leftmost column ---- + if (fvc._fromCol == fc) + { + fromCol = fvc._fromCol; + } + else + { + int r = fromRow, c = fc; + while (_values.NextCellByColumn(ref r, ref c, fromRow, toRow, _values.ColumnCount - 1)) { - int r = fromRow, c = fc; - while (_values.NextCellByColumn(ref r, ref c, fromRow, toRow, _values.ColumnCount - 1)) + if (_values.GetValue(r, c)._value != null) { - if (_values.GetValue(r, c)._value != null) - { - break; - } - r++; + break; } - fromCol = c; + r++; } + fromCol = c; + } - if (lvc._toCol == tc) + // ---- Rightmost column ---- + if (lvc._toCol == tc) + { + toCol = lvc._toCol; + } + else + { + int r = toRow, c = tc; + while (_values.PrevCellByColumn(ref r, ref c, fromRow, toRow, _values.ColumnCount - 1)) { - toCol = lvc._toCol; + if (_values.GetValue(r, c)._value != null) + { + break; + } + r--; } - else + toCol = c; + } + + // ---- Extend column range by visible styling (visibility mode only) ---- + // Scan the whole used column span and pull fromCol/toCol outward to + // include any column that has a visible style somewhere in the row range. + if (byVisibility) + { + for (int c = fc; c <= tc; c++) { - int r = toRow, c = tc; - while (_values.PrevCellByColumn(ref r, ref c, fromRow, toRow, _values.ColumnCount - 1)) + if (c >= fromCol && c <= toCol) + { + continue; // already inside the range + } + for (int r = fromRow; r <= toRow; r++) { - if (_values.GetValue(r, c)._value != null) + if (HasVisibleStyle(r, c)) { - break; + if (c < fromCol) fromCol = c; + if (c > toCol) toCol = c; + break; // this column qualifies; move to the next column } - r--; } - toCol = c; } + } + + return Cells[System.Math.Min(fromRow, toRow), System.Math.Min(fromCol, toCol), System.Math.Max(fromRow, toRow), System.Math.Max(fromCol, toCol)]; + } + return null; + } + + /// + /// Returns true if the cell at (row, col) has a style that is visible on an + /// empty cell: a fill pattern other than None, or a border edge other than + /// None. Invisible styling (font, alignment, number format) is ignored. + /// The style id is resolved through the cell -> row -> column inheritance + /// chain so that fills/borders applied to a whole column or row are detected. + /// + private bool HasVisibleStyle(int row, int col) + { + // Resolve the effective style id, following cell -> row -> column. + int styleId = Workbook.Styles.GetStyleId(this, row, col); + if (styleId <= 0) + { + return false; // 0 == the default style, which is not visible + } + + var styles = Workbook.Styles; + if (styleId >= styles.CellXfs.Count) + { + return false; + } + var xf = styles.CellXfs[styleId]; - return Cells[Math.Min(fromRow, toRow), Math.Min(fromCol, toCol), Math.Max(fromRow, toRow), Math.Max(fromCol, toCol)]; + // --- Fill --- + // FillId 0 is always the "None" fill (see EnsureValidFills). + if (xf.FillId > 0 && xf.FillId < styles.Fills.Count) + { + var fill = styles.Fills[xf.FillId]; + if (fill.PatternType != ExcelFillStyle.None) + { + return true; } - return null; } + + // --- Border --- + // NOTE: verify the member names against the ExcelBorderXml type in core + // EPPlus. The edges are expected to expose a Style of type ExcelBorderStyle. + if (xf.BorderId > 0 && xf.BorderId < styles.Borders.Count) + { + var border = styles.Borders[xf.BorderId]; + if (border.Top.Style != ExcelBorderStyle.None || + border.Bottom.Style != ExcelBorderStyle.None || + border.Left.Style != ExcelBorderStyle.None || + border.Right.Style != ExcelBorderStyle.None || + border.Diagonal.Style != ExcelBorderStyle.None) + { + return true; + } + } + + return false; } + /// /// The first cell with a value in the worksheet that differs from null. /// Normally this is the top-left cell, unless the worksheet is set to RightToLeft mode. diff --git a/src/EPPlus/Export/HtmlExport/CssCollections/CssChartRuleCollection.cs b/src/EPPlus/Export/HtmlExport/CssCollections/CssChartRuleCollection.cs new file mode 100644 index 0000000000..453c7791e9 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/CssCollections/CssChartRuleCollection.cs @@ -0,0 +1,172 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport.Exporters.Internal; +using OfficeOpenXml.Export.HtmlExport.Settings; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors; +using OfficeOpenXml.Export.HtmlExport.Translators; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.CssCollections +{ + internal class CssChartRuleCollection : CssRuleCollection + { + CssExportSettings _settings; + ExcelChart _chart; + ExcelTheme _theme; + TranslatorContext _context; + + public CssChartRuleCollection(ExcelChart chart, CssExportSettings settings) + { + _chart = chart; + _settings = settings; + + if (_chart.WorkSheet.Workbook.ThemeManager.CurrentTheme == null) + { + _chart.WorkSheet.Workbook.ThemeManager.CreateDefaultTheme(); + } + _theme = _chart.WorkSheet.Workbook.ThemeManager.CurrentTheme; + + _context = new TranslatorContext(settings); + _context.Theme = _theme; + + //RuleCollection = new CssRuleCollection(); + + AddChartFillToCollection(chart, "epp-"); + } + + internal void AddChartFillToCollection(ExcelChart chart, string chartClassPreset) + { + var chartClass = $"{chartClassPreset}{HtmlExportTableUtil.GetClassName(chart.Name, $"chartstyle{chart.Id}")}"; + + var s = chart.StyleManager.Style; + + if(s == null) + { + chart.StyleManager.ApplyStyles(); + } + + s = chart.StyleManager.Style; + + if (s != null) + { + + var chartAreaRef = chart.StyleManager.Style.ChartArea.FillReference.Color; + + AddToCollection(chartClass, chart.Fill, chart.Border, "rect"); + + + //var fallbackElementBorder = chart.StyleManager.Style.ChartArea.BorderReference.Color; + + //AddToCollection(chartClass, chart.Border, "border"); + } + } + + internal void AddToCollection(string name, ExcelDrawingBorder element, string htmlElement) + { + //if (element) return; //Dont add empty elements + + var s = element; + + var styleClass = new CssRule($"{htmlElement}.{name}", int.MaxValue); + + var translators = new List(); + + if (element != null && _context.Exclude.Fill == false) + { + //TODO: Ensure if gradients with more than 2 colors it is handled correctly. + translators.Add(new CssFillTranslator(new FillDrawingBasic(element.Fill))); + } + //if (s.Font != null && _context.Exclude.Font != eFontExclude.All) + //{ + // translators.Add(new CssFontTranslator(new FontDxf(s.Font), null)); + //} + //if (s.Border != null && _context.Exclude.Border != eBorderExclude.All) + //{ + // translators.Add(new CssBorderTranslator(new BorderDxf(s.Border))); + //} + + foreach (var translator in translators) + { + _context.SetTranslator(translator); + _context.AddDeclarations(styleClass); + } + + AddRule(styleClass); + } + + internal void AddToCollection(string name, ExcelDrawingFill element, ExcelDrawingBorder border, string htmlElement) + { + if (element.IsEmpty) return; //Dont add empty elements + + var s = element; + + var styleClass = new CssRule($"{htmlElement}.{name}", int.MaxValue); + + var translators = new List(); + + if (element != null && _context.Exclude.Fill == false) + { + var fillGeneric = new FillDrawing(element); + var fillTranslator = new CssFillTranslator(fillGeneric, true); + //TODO: Ensure if gradients with more than 2 colors it is handled correctly. + translators.Add(fillTranslator); + } + //if (s.Font != null && _context.Exclude.Font != eFontExclude.All) + //{ + // translators.Add(new CssFontTranslator(new FontDxf(s.Font), null)); + //} + if (border != null && _context.Exclude.Border != eBorderExclude.All) + { + + translators.Add(new CssStrokeTranslator(new BorderDrawing(border))); + } + + foreach (var translator in translators) + { + _context.SetTranslator(translator); + _context.AddDeclarations(styleClass); + } + + AddRule(styleClass); + } + + internal void AddToCollection(string name, ExcelChartStyleItem element, string htmlElement) + { + if (element.HasValue() == false) return; //Dont add empty elements + + var s = element; + + var styleClass = new CssRule($"{htmlElement}.{name}", int.MaxValue); + + var translators = new List(); + + if (s.Fill != null && _context.Exclude.Fill == false) + { + translators.Add(new CssFillTranslator(new FillDrawing(s.Fill))); + } + //if (s.Font != null && _context.Exclude.Font != eFontExclude.All) + //{ + // translators.Add(new CssFontTranslator(new FontDxf(s.Font), null)); + //} + //if (s.Border != null && _context.Exclude.Border != eBorderExclude.All) + //{ + // translators.Add(new CssBorderTranslator(new BorderDxf(s.Border))); + //} + + foreach (var translator in translators) + { + _context.SetTranslator(translator); + _context.AddDeclarations(styleClass); + } + + AddRule(styleClass); + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/CssCollections/CssRangeRuleCollection.cs b/src/EPPlus/Export/HtmlExport/CssCollections/CssRangeRuleCollection.cs index 77232f1a71..d4f68965e9 100644 --- a/src/EPPlus/Export/HtmlExport/CssCollections/CssRangeRuleCollection.cs +++ b/src/EPPlus/Export/HtmlExport/CssCollections/CssRangeRuleCollection.cs @@ -427,7 +427,31 @@ internal void AddIconSetCF(ExcelConditionalFormattingIconSetBase set, int _ruleCollection.CssRules.Add(contentRule); } + internal void AddDrawingToCss(HtmlSvgDrawing d) + { + var translator = new CssImageTranslator(d); + + if (translator.type == null) return; + + string imageFileName = HtmlExportTableUtil.GetClassName(d.Drawing.Name, "optional-name"); + var imgRule = new CssRule($"img.{_settings.StyleClassPrefix}drawing-{imageFileName}", int.MaxValue); + + _context.SetTranslator(translator); + _context.AddDeclarations(imgRule); + _ruleCollection.AddRule(imgRule); + + AddDrawingPropertiesToCss(d); + } + internal void AddDrawingPropertiesToCss(HtmlSvgDrawing d) + { + string imageName = HtmlExportTableUtil.GetClassName(d.Drawing.Name, "optional-name"); + + var imgProperties = new CssRule($"img.{_settings.StyleClassPrefix}drawing-prop-{imageName}", int.MaxValue); + _context.SetTranslator(new CssDrawingPropertiesTranslator(d)); + _context.AddDeclarations(imgProperties); + RuleCollection.AddRule(imgProperties); + } internal void AddPictureToCss(HtmlImage p) { diff --git a/src/EPPlus/Export/HtmlExport/Enums/eDrawingInclude.cs b/src/EPPlus/Export/HtmlExport/Enums/eDrawingInclude.cs new file mode 100644 index 0000000000..d092f66c83 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Enums/eDrawingInclude.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport +{ + /// + /// What drawings to include in html export + /// + [Flags] + public enum eDrawingInclude + { + /// + /// Include no drawings + /// + None = 0, + /// + /// Include Shapes + /// + Shapes = 2, + /// + /// Include Charts + /// + Charts = 4, + + //TODO: This is already handled by image enum. We may need restructure here + /// + /// Include Images ? + /// + Images = 8, + } +} diff --git a/src/EPPlus/Export/HtmlExport/Enums/ePicturePosition.cs b/src/EPPlus/Export/HtmlExport/Enums/ePicturePosition.cs index 5a2c4eeae9..4252a49e49 100644 --- a/src/EPPlus/Export/HtmlExport/Enums/ePicturePosition.cs +++ b/src/EPPlus/Export/HtmlExport/Enums/ePicturePosition.cs @@ -14,7 +14,7 @@ Date Author Change namespace OfficeOpenXml.Export.HtmlExport { /// - /// If the Picture is absolut or relative to the table cell + /// If the Blip is absolut or relative to the table cell /// public enum ePicturePosition { diff --git a/src/EPPlus/Export/HtmlExport/Exporters/Internal/AbstractRangeExporter.cs b/src/EPPlus/Export/HtmlExport/Exporters/Internal/AbstractRangeExporter.cs index 61cc6bc4e5..ca8d63f8bf 100644 --- a/src/EPPlus/Export/HtmlExport/Exporters/Internal/AbstractRangeExporter.cs +++ b/src/EPPlus/Export/HtmlExport/Exporters/Internal/AbstractRangeExporter.cs @@ -11,6 +11,7 @@ Date Author Change 6/4/2022 EPPlus Software AB ExcelTable Html Export *************************************************************************************************/ using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using OfficeOpenXml.Table; using OfficeOpenXml.Utils.String; @@ -27,6 +28,7 @@ public AbstractHtmlExporter() internal const string TableClass = "epplus-table"; internal List _rangePictures = null; + internal List _rangeDrawings = null; protected List _dataTypes = new List(); protected ExporterContext _exporterContext; @@ -45,13 +47,14 @@ protected void GetDataTypes(ExcelAddressBase adr, ExcelTable table) } } - internal void LoadRangeImages(List ranges) + internal void LoadRangeDrawings(List ranges) { if (_rangePictures != null) { return; } _rangePictures = new List(); + _rangeDrawings = new List(); //Render in-cell images. foreach (var worksheet in ranges.Select(x => x.Worksheet).Distinct()) { @@ -76,6 +79,44 @@ internal void LoadRangeImages(List ranges) ToColumnOff = toColOff }); } + else if(d is ExcelShape s) + { + s.GetFromBounds(out int fromRow, out int fromRowOff, out int fromCol, out int fromColOff); + s.GetToBounds(out int toRow, out int toRowOff, out int toCol, out int toColOff); + + _rangeDrawings.Add(new HtmlSvgDrawing() + { + WorksheetId = worksheet.PositionId, + Drawing = s, + FromRow = fromRow, + FromRowOff = fromRowOff, + FromColumn = fromCol, + FromColumnOff = fromColOff, + ToRow = toRow, + ToRowOff = toRowOff, + ToColumn = toCol, + ToColumnOff = toColOff + }); + } + else if(d is ExcelChart) + { + d.GetFromBounds(out int fromRow, out int fromRowOff, out int fromCol, out int fromColOff); + d.GetToBounds(out int toRow, out int toRowOff, out int toCol, out int toColOff); + + _rangeDrawings.Add(new HtmlSvgDrawing() + { + WorksheetId = worksheet.PositionId, + Drawing = d, + FromRow = fromRow, + FromRowOff = fromRowOff, + FromColumn = fromCol, + FromColumnOff = fromColOff, + ToRow = toRow, + ToRowOff = toRowOff, + ToColumn = toCol, + ToColumnOff = toColOff + }); + } } } } @@ -114,5 +155,18 @@ protected HtmlImage GetImage(int worksheetId, int row, int col) } return null; } + + protected HtmlSvgDrawing GetDrawing(int worksheetId, int row, int col) + { + if (_rangeDrawings == null) return null; + foreach (var d in _rangeDrawings) + { + if (d.FromRow == row - 1 && d.FromColumn == col - 1 && d.WorksheetId == worksheetId) + { + return d; + } + } + return null; + } } } diff --git a/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssChartExporterSync.cs b/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssChartExporterSync.cs new file mode 100644 index 0000000000..4374a53e91 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssChartExporterSync.cs @@ -0,0 +1,102 @@ +using OfficeOpenXml.ConditionalFormatting; +using OfficeOpenXml.ConditionalFormatting.Contracts; +using OfficeOpenXml.ConditionalFormatting.Rules; +using OfficeOpenXml.Core; +using OfficeOpenXml.Core.CellStore; +using OfficeOpenXml.Core.RangeQuadTree; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Export.HtmlExport.CssCollections; +using OfficeOpenXml.Export.HtmlExport.Determinator; +using OfficeOpenXml.Export.HtmlExport.Settings; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Export.HtmlExport.Translators; +using OfficeOpenXml.Export.HtmlExport.Writers; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Table; +using OfficeOpenXml.Utils; +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace OfficeOpenXml.Export.HtmlExport.Exporters.Internal +{ + internal class CssChartExporterSync + { + CssExportSettings _settings; + + ExcelChart _chart; + + TranslatorContext _context; + + public CssChartExporterSync(ExcelChart chart) : this(new CssChartExportSettings(), chart) + { + + } + + public CssChartExporterSync(CssChartExportSettings settings, ExcelChart chart) + { + _settings = settings; + Require.Argument(chart).IsNotNull("chart"); + _chart = chart; + } + /// + /// Exports an to a html string + /// + /// A html table + public string GetCssString() + { + using (var ms = EPPlusMemoryManager.GetStream()) + { + RenderCss(ms); + ms.Position = 0; + using (var sr = new StreamReader(ms)) + { + return sr.ReadToEnd(); + } + } + } + /// + /// Exports the css part of the html export. + /// + /// The stream to write the css to. + /// + public void RenderCss(Stream stream) + { + var trueWriter = new CssWriter(stream); + + var cssCollection = new CssChartRuleCollection(_chart, _settings); + + trueWriter.WriteAndClearFlush(cssCollection, false); + } + + // /// + // /// Exports the css part of an to a html string + // /// + // /// A html table + // public void RenderCss(Stream stream) + // { + // var cssWriter = GetTableCssWriter(stream, _table, _tableSettings); + // if (cssWriter == null) { return; } + + // var cssRules = CreateRuleCollection(_tableSettings); + // cssWriter.WriteAndClearFlush(cssRules, Settings.Minify); + // } + + // protected CssRuleCollection CreateRuleCollection(CssExportSettings settings) + // { + // var cssTranslator = new CssChartRuleCollection(_chart, settings); + + // _context = new TranslatorContext(settings); + + + // //AddCssRulesToCollection(cssTranslator, settings); + + // //return cssTranslator.RuleCollection; + // } + + } + } diff --git a/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssExporterBase.cs b/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssExporterBase.cs index e6bdbc9b67..74dada4db1 100644 --- a/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssExporterBase.cs +++ b/src/EPPlus/Export/HtmlExport/Exporters/Internal/CssExporterBase.cs @@ -11,10 +11,12 @@ Date Author Change 6/4/2022 EPPlus Software AB ExcelTable Html Export *************************************************************************************************/ using OfficeOpenXml.ConditionalFormatting; +using OfficeOpenXml.ConditionalFormatting.Contracts; using OfficeOpenXml.ConditionalFormatting.Rules; using OfficeOpenXml.Core; using OfficeOpenXml.Core.CellStore; using OfficeOpenXml.Core.RangeQuadTree; +using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Export.HtmlExport.CssCollections; using OfficeOpenXml.Export.HtmlExport.Determinator; using OfficeOpenXml.Export.HtmlExport.Settings; @@ -26,10 +28,9 @@ Date Author Change using OfficeOpenXml.Utils; using System; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; -using OfficeOpenXml.ConditionalFormatting.Contracts; -using System.Data; using System.Runtime.CompilerServices; namespace OfficeOpenXml.Export.HtmlExport.Exporters.Internal @@ -136,14 +137,23 @@ protected void AddCssRulesToCollection(CssRangeRuleCollection cssTranslator, Htm } } - if (Settings.Pictures.Include == ePictureInclude.Include) + if (Settings.Pictures.Include == ePictureInclude.Include || Settings.Pictures.Include == ePictureInclude.IncludeInCssOnly) { - LoadRangeImages(_ranges._list); + LoadRangeDrawings(_ranges._list); foreach (var p in _rangePictures) { cssTranslator.AddPictureToCss(p); } } + + if(Settings.Drawings.Include == ePictureInclude.Include || Settings.Drawings.Include == ePictureInclude.IncludeInCssOnly) + { + LoadRangeDrawings(_ranges._list); + foreach(var d in _rangeDrawings) + { + cssTranslator.AddDrawingToCss(d); + } + } } protected void AddCellCss(CssRangeRuleCollection collection, ExcelRangeBase range, bool isTableExporter = false) diff --git a/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlExporterBaseInternal.cs b/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlExporterBaseInternal.cs index 550687db2c..997be280a4 100644 --- a/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlExporterBaseInternal.cs +++ b/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlExporterBaseInternal.cs @@ -51,7 +51,7 @@ public HtmlExporterBaseInternal(HtmlExportSettings settings, ExcelRangeBase rang } } - LoadRangeImages(_ranges._list); + LoadRangeDrawings(_ranges._list); } public HtmlExporterBaseInternal(HtmlExportSettings settings, EPPlusReadOnlyList ranges) @@ -60,7 +60,7 @@ public HtmlExporterBaseInternal(HtmlExportSettings settings, EPPlusReadOnlyList< Require.Argument(ranges).IsNotNull("ranges"); _ranges = ranges; //TODO: Fix support for all ranges - LoadRangeImages(_ranges._list); + LoadRangeDrawings(_ranges._list); } protected void SetColumnGroup(HTMLElement element, ExcelRangeBase _range, HtmlExportSettings settings, bool isMultiSheet) @@ -122,6 +122,7 @@ protected HTMLElement GetThead(ExcelRangeBase range, List headers = null ExcelWorksheet worksheet = range.Worksheet; HtmlImage image = null; + HtmlSvgDrawing drawing = null; foreach (var col in _columns) { if (InMergeCellSpan(row, col)) continue; @@ -154,7 +155,13 @@ protected HTMLElement GetThead(ExcelRangeBase range, List headers = null image = GetImage(cell.Worksheet.PositionId, cell._fromRow, cell._fromCol); } + if ((Settings.Drawings.Include == ePictureInclude.Include) || (Settings.Drawings.Include == ePictureInclude.IncludeInHtmlOnly)) + { + drawing = GetDrawing(cell.Worksheet.PositionId, cell._fromRow, cell._fromCol); + } + AddImage(contentElement, Settings, image, cell.Value); + AddDrawing(contentElement, Settings, drawing, cell.Value); if (headerRows > 0 || table != null) { @@ -225,6 +232,7 @@ protected HTMLElement GetTableBody(ExcelRangeBase range, int row, int endRow) var ws = range.Worksheet; HtmlImage image = null; + HtmlDrawing drawing = null; bool hasFooter = table != null && table.ShowTotal; while (row <= endRow) { @@ -275,6 +283,11 @@ protected HTMLElement GetTableBody(ExcelRangeBase range, int row, int endRow) image = GetImage(cell.Worksheet.PositionId, cell._fromRow, cell._fromCol); } + if (Settings.Drawings.Include == (ePictureInclude.Include | ePictureInclude.IncludeInHtmlOnly)) + { + drawing = GetDrawing(cell.Worksheet.PositionId, cell._fromRow, cell._fromCol); + } + if (cell.Hyperlink == null) { var addRowScope = table == null ? false : table.ShowFirstColumn && col == table.Address._fromCol || table.ShowLastColumn && col == table.Address._toCol; @@ -430,6 +443,35 @@ protected void AddImage(HTMLElement parent, HtmlExportSettings settings, HtmlIma } } + protected void AddDrawing(HTMLElement parent, HtmlExportSettings settings, HtmlSvgDrawing d, object value) + { + if (d != null) + { + var child = new HTMLElement(HtmlElements.Img); + string drawingName = HtmlExportTableUtil.GetClassName(d.Drawing.Name, $"drawing{d.Drawing.Id}"); + child.AddAttribute("alt", d.Drawing.Name); + if (settings.Pictures.AddNameAsId) + { + child.AddAttribute("id", drawingName); + } + + if (settings.Drawings.Include == ePictureInclude.IncludeInHtmlOnly) + { + child = new HTMLElement(HtmlElements.Svg); + child.ElementName = "div"; + child.Content = d.Drawing.ToSvg(); + //var _encodedImage = ImageEncoder.EncodeImage(image, out type); + + //child.AddAttribute("src", $"data:{GetContentType(type.Value)};base64,{_encodedImage}"); + } + else + { + child.AddAttribute("class", $"{settings.StyleClassPrefix}drawing-{drawingName} {settings.StyleClassPrefix}drawing-prop-{drawingName}"); + } + parent._childElements.Add(child); + } + } + protected List _columns = new List(); protected HtmlExportSettings Settings; protected readonly List _mergedCells = new List(); diff --git a/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlTableExporterBase.cs b/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlTableExporterBase.cs index 9648722f95..64633caec8 100644 --- a/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlTableExporterBase.cs +++ b/src/EPPlus/Export/HtmlExport/Exporters/Internal/HtmlTableExporterBase.cs @@ -31,7 +31,7 @@ internal HtmlTableExporterBase _table = table; _tableExportSettings = settings; - LoadRangeImages(new List() { table.Range }); + LoadRangeDrawings(new List() { table.Range }); } protected readonly ExcelTable _table; diff --git a/src/EPPlus/Export/HtmlExport/HtmlCollections/HTMLElement.cs b/src/EPPlus/Export/HtmlExport/HtmlCollections/HTMLElement.cs index 0981099422..0b471d7b14 100644 --- a/src/EPPlus/Export/HtmlExport/HtmlCollections/HTMLElement.cs +++ b/src/EPPlus/Export/HtmlExport/HtmlCollections/HTMLElement.cs @@ -36,6 +36,11 @@ internal HTMLElement(string elementName) } } + /// + /// Add attribute with a value + /// + /// + /// public void AddAttribute(string attributeName, string attributeValue) { Require.Argument(attributeName).IsNotNullOrEmpty("attributeName"); @@ -43,13 +48,20 @@ public void AddAttribute(string attributeName, string attributeValue) _attributes.Add(new EpplusHtmlAttribute { AttributeName = attributeName, Value = attributeValue }); } - + /// + /// Add attribute without it having a value + /// + /// public void AddAttributeValueLess(string attributeName) { Require.Argument(attributeName).IsNotNullOrEmpty("attributeName"); _attributes.Add(new EpplusHtmlAttribute { AttributeName = attributeName }); } + /// + /// Add child element + /// + /// public void AddChildElement(HTMLElement element) { _childElements.Add(element); diff --git a/src/EPPlus/Export/HtmlExport/HtmlDrawing.cs b/src/EPPlus/Export/HtmlExport/HtmlDrawing.cs new file mode 100644 index 0000000000..61836e5710 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/HtmlDrawing.cs @@ -0,0 +1,21 @@ +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport +{ + internal class HtmlDrawing + { + public int WorksheetId { get; set; } + public int FromRow { get; set; } + public int FromRowOff { get; set; } + public int ToRow { get; set; } + public int ToRowOff { get; set; } + public int FromColumn { get; set; } + public int FromColumnOff { get; set; } + public int ToColumn { get; set; } + public int ToColumnOff { get; set; } + } +} diff --git a/src/EPPlus/Export/HtmlExport/HtmlElements.cs b/src/EPPlus/Export/HtmlExport/HtmlElements.cs index 8f32db0ca0..9822084b40 100644 --- a/src/EPPlus/Export/HtmlExport/HtmlElements.cs +++ b/src/EPPlus/Export/HtmlExport/HtmlElements.cs @@ -46,5 +46,6 @@ internal static readonly HashSet NoIndentElements public const string Span = "span"; public const string ColGroup = "colgroup"; public const string Img = "img"; + public const string Svg = "svg"; } } diff --git a/src/EPPlus/Export/HtmlExport/HtmlImage.cs b/src/EPPlus/Export/HtmlExport/HtmlImage.cs index 4ee719a7a9..a5256cb624 100644 --- a/src/EPPlus/Export/HtmlExport/HtmlImage.cs +++ b/src/EPPlus/Export/HtmlExport/HtmlImage.cs @@ -14,17 +14,8 @@ Date Author Change namespace OfficeOpenXml.Export.HtmlExport { - internal class HtmlImage + internal class HtmlImage : HtmlDrawing { - public int WorksheetId { get; set; } public ExcelPicture Picture { get; set; } - public int FromRow { get; set; } - public int FromRowOff { get; set; } - public int ToRow { get; set; } - public int ToRowOff { get; set; } - public int FromColumn { get; set; } - public int FromColumnOff { get; set; } - public int ToColumn { get; set; } - public int ToColumnOff { get; set; } } } diff --git a/src/EPPlus/Export/HtmlExport/HtmlSvgDrawing.cs b/src/EPPlus/Export/HtmlExport/HtmlSvgDrawing.cs new file mode 100644 index 0000000000..19275c6b09 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/HtmlSvgDrawing.cs @@ -0,0 +1,13 @@ +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport +{ + internal class HtmlSvgDrawing : HtmlDrawing + { + public ExcelDrawing Drawing; + } +} diff --git a/src/EPPlus/Export/HtmlExport/Settings/CssChartExportSettings.cs b/src/EPPlus/Export/HtmlExport/Settings/CssChartExportSettings.cs new file mode 100644 index 0000000000..4d9ed35731 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Settings/CssChartExportSettings.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.Settings +{ + internal class CssChartExportSettings : CssExportSettings + { + public CssChartExportSettings() : base() + { + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/Settings/HtmlDrawingSettings.cs b/src/EPPlus/Export/HtmlExport/Settings/HtmlDrawingSettings.cs new file mode 100644 index 0000000000..d94bfbb869 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Settings/HtmlDrawingSettings.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport +{ + public class HtmlDrawingSettings + { + internal HtmlDrawingSettings() + { + + } + + //Use picture for now. Possibly re-name + /// + /// If how drawings should be included in the html. Default is + /// + public ePictureInclude Include = ePictureInclude.Exclude; + + /// + /// Which type of drawing should be included + /// + public eDrawingInclude DrawTypeInclude = eDrawingInclude.None; + + /// + /// Is absolute by default for charts + /// + public ePicturePosition Position = ePicturePosition.DontSet; + + } +} diff --git a/src/EPPlus/Export/HtmlExport/Settings/HtmlExportSettings.cs b/src/EPPlus/Export/HtmlExport/Settings/HtmlExportSettings.cs index a00017fdca..5cde7470e7 100644 --- a/src/EPPlus/Export/HtmlExport/Settings/HtmlExportSettings.cs +++ b/src/EPPlus/Export/HtmlExport/Settings/HtmlExportSettings.cs @@ -92,7 +92,7 @@ public string DataValueAttributeName /// Alignment Right{StyleClassPrefix}ar /// Default column width{StyleClassPrefix}dcw /// Default row height{StyleClassPrefix}drh - /// Image content and position{StyleClassPrefix}image-{imageName} + /// BulletImage content and position{StyleClassPrefix}image-{imageName} /// Properties for an image, for example position or border settings{StyleClassPrefix}image-prop-{imageName} /// Alignment for cells containing an image{StyleClassPrefix}image-cell} /// @@ -136,6 +136,13 @@ public HtmlPictureSettings Pictures { get; } = new HtmlPictureSettings(); + /// + /// If and which Charts and/or Shapes will be included + /// + public HtmlDrawingSettings Drawings + { + get; + } = new HtmlDrawingSettings(); /// /// If set to true classes that identifies Excel table styling will be included in the html. Default value is true. diff --git a/src/EPPlus/Export/HtmlExport/Settings/HtmlPictureSettings.cs b/src/EPPlus/Export/HtmlExport/Settings/HtmlPictureSettings.cs index fabec04d8e..366f25e081 100644 --- a/src/EPPlus/Export/HtmlExport/Settings/HtmlPictureSettings.cs +++ b/src/EPPlus/Export/HtmlExport/Settings/HtmlPictureSettings.cs @@ -53,7 +53,7 @@ internal HtmlPictureSettings() /// public PictureCssExclude CssExclude { get; } = new PictureCssExclude(); /// - /// Adds the Picture name as Id for the img element in the HTML. + /// Adds the Blip name as Id for the img element in the HTML. /// Characters [A-Z][0-9]-_ are allowed. The first character allows [A-Z]_. /// Other characters will be replaced with an hyphen (-). /// diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawing.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawing.cs new file mode 100644 index 0000000000..932ee0e0d1 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawing.cs @@ -0,0 +1,24 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.Dxf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +{ + internal class BorderDrawing : IDrawingBorder + { + ExcelDrawingBorder _border; + + internal BorderDrawing(ExcelDrawingBorder border) + { + _border = border; + Stroke = new FillDrawingBasic(border.Fill); + } + + public IFill Stroke { get; private set; } + } +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawingAlt.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawingAlt.cs new file mode 100644 index 0000000000..90478306ab --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderDrawingAlt.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +{ + internal class BorderDrawingAlt + { + } +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderItemDrawing.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderItemDrawing.cs new file mode 100644 index 0000000000..8e7ef14f7d --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/BorderItemDrawing.cs @@ -0,0 +1,23 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +{ + //internal class BorderItemDrawing : IBorderItem + //{ + // public BorderItemDrawing(ExcelDrawingBorder border) + // { + // var fill = new FillDrawingBasic(border.Fill); + // //border.Fill.Color + // } + + // ExcelBorderStyle IBorderItem.Style => throw new NotImplementedException(); + + // IStyleColor IBorderItem.Color => throw new NotImplementedException(); + //} +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawing.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawing.cs new file mode 100644 index 0000000000..cfdd47818a --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawing.cs @@ -0,0 +1,145 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.Dxf; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +{ + internal class FillDrawing : IFill + { + ExcelDrawingFill _fill; + + internal FillDrawing(ExcelDrawingFill fill) + { + _fill = fill; + } + + public bool IsGradient + { + get + { + return _fill.Style == eFillStyle.GradientFill; + } + } + + + public bool IsLinear + { + get + { + return _fill.GradientFill.ShadePath == eShadePath.Linear; + } + } + + + public double Degree + { + get + { + if (IsGradient) + { + if(IsLinear) + { + return _fill.GradientFill.LinearSettings.Angle; + } + } + + return double.NaN; + } + } + + + + public double Right + { + get + { + if (IsGradient) + { + if(IsLinear == false) + { + return _fill.GradientFill.TileRectangle.RightOffset; + } + } + + return double.NaN; + } + } + + public double Bottom + { + get + { + if (IsGradient) + { + if (IsLinear == false) + { + return _fill.GradientFill.TileRectangle.BottomOffset; + } + } + + return double.NaN; + } + } + + public string GetBackgroundColor(ExcelTheme theme) + { + return GetColor(_fill.Color, theme); + } + + public string GetPatternColor(ExcelTheme theme) + { + return GetColor(_fill.PatternFill.ForegroundColor.GetColor(), theme); + } + + public string GetGradientColor1(ExcelTheme theme) + { + return GetColor(_fill.GradientFill.Colors.ToArray()[0].Color.GetColor(), theme); + } + public string GetGradientColor2(ExcelTheme theme) + { + return GetColor(_fill.GradientFill.Colors.ToArray()[1].Color.GetColor(), theme); + } + + public bool HasValue + { + get + { + return !_fill.IsEmpty; + } + } + + ExcelFillStyle IFill.PatternType => ExcelFillStyle.Solid; + + internal static string GetColor(Color c, ExcelTheme theme) + { + return "#" + c.ToArgb().ToString("x8").Substring(2); + } + + string IFill.GetBackgroundColor(ExcelTheme theme) + { + return GetBackgroundColor(theme); + } + + string IFill.GetPatternColor(ExcelTheme theme) + { + return GetPatternColor(theme); + } + + string IFill.GetGradientColor1(ExcelTheme theme) + { + return GetGradientColor1(theme); + } + + string IFill.GetGradientColor2(ExcelTheme theme) + { + return GetGradientColor2(theme); + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawingBasic.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawingBasic.cs new file mode 100644 index 0000000000..9841790876 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/FillDrawingBasic.cs @@ -0,0 +1,144 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +{ + internal class FillDrawingBasic : IFill + { + ExcelDrawingFillBasic _fill; + + internal FillDrawingBasic(ExcelDrawingFillBasic fill) + { + _fill = fill; + } + + public bool IsGradient + { + get + { + return _fill.Style == eFillStyle.GradientFill; + } + } + + + public bool IsLinear + { + get + { + return _fill.GradientFill.ShadePath == eShadePath.Linear; + } + } + + + public double Degree + { + get + { + if (IsGradient) + { + if (IsLinear) + { + return _fill.GradientFill.LinearSettings.Angle; + } + } + + return double.NaN; + } + } + + + + public double Right + { + get + { + if (IsGradient) + { + if (IsLinear == false) + { + return _fill.GradientFill.TileRectangle.RightOffset; + } + } + + return double.NaN; + } + } + + public double Bottom + { + get + { + if (IsGradient) + { + if (IsLinear == false) + { + return _fill.GradientFill.TileRectangle.BottomOffset; + } + } + + return double.NaN; + } + } + + public string GetBackgroundColor(ExcelTheme theme) + { + return GetColor(_fill.Color, theme); + } + + public string GetPatternColor(ExcelTheme theme) + { + return GetColor(Color.Empty, theme); + } + + public string GetGradientColor1(ExcelTheme theme) + { + return GetColor(_fill.GradientFill.Colors.ToArray()[0].Color.GetColor(), theme); + } + public string GetGradientColor2(ExcelTheme theme) + { + return GetColor(_fill.GradientFill.Colors.ToArray()[1].Color.GetColor(), theme); + } + + public bool HasValue + { + get + { + return !_fill.IsEmpty; + } + } + + public ExcelFillStyle PatternType => ExcelFillStyle.Solid; + + internal static string GetColor(Color c, ExcelTheme theme) + { + return "#" + c.ToArgb().ToString("x8").Substring(2); + } + + string IFill.GetBackgroundColor(ExcelTheme theme) + { + return GetBackgroundColor(theme); + } + + string IFill.GetPatternColor(ExcelTheme theme) + { + return GetPatternColor(theme); + } + + string IFill.GetGradientColor1(ExcelTheme theme) + { + return GetGradientColor1(theme); + } + + string IFill.GetGradientColor2(ExcelTheme theme) + { + return GetGradientColor2(theme); + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleColorDrawing.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleColorDrawing.cs new file mode 100644 index 0000000000..68463da7e2 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleColorDrawing.cs @@ -0,0 +1,43 @@ +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +//{ +// internal class StyleColorDrawing : IStyleColor +// { + // public StyleColorDrawing() + // { + // } + + // ExcelColor _color; + + // //TODO: Is this correct? + // public bool Exists { get { return true; } } + + // public bool Auto { get { return _color.Auto; } } + + // public int Indexed { get { return _color.Indexed; } } + + // public double Tint { get { return (double)_color.Tint; } } + + // public eThemeSchemeColor? Theme { get { return _color.Theme; } } + + // public string Rgb { get { return _color.Rgb; } } + + // public bool AreColorEqual(IStyleColor color) + // { + // return StyleColorShared.AreColorEqual(this, color); + // } + + // public string GetColor(ExcelTheme theme) + // { + // return StyleColorShared.GetColor(this, theme); + // } + //} +//} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleContracts/IDrawingBorder.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleContracts/IDrawingBorder.cs new file mode 100644 index 0000000000..b3cbe1d495 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleContracts/IDrawingBorder.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts +{ + public interface IDrawingBorder + { + IFill Stroke { get; } + } +} diff --git a/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleDrawing.cs b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleDrawing.cs new file mode 100644 index 0000000000..4cbc1dcf79 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/StyleCollectors/StyleDrawing.cs @@ -0,0 +1,72 @@ +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using OfficeOpenXml.Style.Dxf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//namespace OfficeOpenXml.Export.HtmlExport.StyleCollectors +//{ +// internal class StyleDrawing : IStyleExport +// { +// //ExcelChartStyleEntry _style; + +// //public bool HasStyle +// //{ +// // get { return _style.HasFill; } +// //} + +// //public string StyleKey { get; } = null; /*{ get { return _style.Id; } }*/ + +// //public IFill Fill { get; } = null; +// //public IFont Font { get; } = null; +// //public IBorder Border { get; } = null; +// //public INumberFormat NumberFormat { get; } = null; + +// ////Charts never have a checkbox. Break out of baseClass? +// //bool IStyleExport.CheckBox => false; + +// //public int StyleId; + +// //public StyleDrawing(ExcelChartStyleEntry style, int styleId) +// //{ +// // _style = style; +// // StyleId = styleId; + +// // if (style.HasFill) +// // { +// // Fill = new FillDrawing(style.Fill); +// // } +// // if (style.HasTextBody) +// // { +// // //not implemented yet +// // if (style.HasRichText) +// // { +// // if(style.HasTextRun) +// // { +// // //style.FontReference +// // } +// // } +// // //Font = new FontDxf(style.Font); +// // } +// // if(style.FontReference != null) +// // { +// // //not implemented yet +// // } +// // if (style.HasBorder) +// // { +// // //style.Border. +// // //var lineStyle = style.Border.LineStyle; +// // //Border.Top.Style = Style.ExcelBorderStyle. +// // //Border = new FillDrawingBasic(style.Border.Fill); +// // } +// // //if (style. != null && style.NumberFormat.HasValue) +// // //{ +// // // NumberFormat = new NumberFormatDxf(style.NumberFormat, styleId); +// // //} + +// // //CheckBox = false; +// //} +// } +//} diff --git a/src/EPPlus/Export/HtmlExport/Translators/CssDrawingPropertiesTranslator.cs b/src/EPPlus/Export/HtmlExport/Translators/CssDrawingPropertiesTranslator.cs new file mode 100644 index 0000000000..94a2701e32 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Translators/CssDrawingPropertiesTranslator.cs @@ -0,0 +1,113 @@ +using EPPlus.Export.Utils; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Export.HtmlExport.CssCollections; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OfficeOpenXml.Export.HtmlExport.Translators +{ + internal class CssDrawingPropertiesTranslator : TranslatorBase + { + + double _width; + double _height; + BoundingBox _bounds; + ExcelDrawingBorder _border; + + internal CssDrawingPropertiesTranslator(HtmlSvgDrawing d) + { + _width = d.Drawing.GetPixelWidth(); + _height = d.Drawing.GetPixelHeight(); + _bounds = d.Drawing.GetBoundingBox(); + if(d.Drawing is ExcelChart) + { + _border = d.Drawing.As.Chart.Chart.Border; + } + else if(d.Drawing is ExcelShapeBase) + { + _border = d.Drawing.As.Shape.Border; + } + } + + internal override List GenerateDeclarationList(TranslatorContext context) + { + if (context.Drawings.Position == ePicturePosition.Relative) + { + if (_bounds.Left != 0) + { + AddDeclaration("left", $"{_bounds.Left.PointToPixel():F0}px"); + } + if (_bounds.Top != 0) + { + AddDeclaration("top", $"{_bounds.Top.PointToPixel():F0}px"); + } + } + else if (context.Drawings.Position == ePicturePosition.Absolute) + { + if (_bounds.Left != 0) + { + AddDeclaration("left", $"{_bounds.GlobalLeft.PointToPixel():F0}px"); + } + if (_bounds.Top != 0) + { + AddDeclaration("top", $"{_bounds.GlobalTop.PointToPixel():F0}px"); + } + } + + if (context.Pictures.KeepOriginalSize == false) + { + if (_width != _bounds.Width) + { + AddDeclaration("max-width", $"{_width:F0}px"); + } + if (_height != _bounds.Height) + { + AddDeclaration("max-height", $"{_height:F0}px"); + } + } + + if (_border.LineStyle != null && context.Pictures.CssExclude.Border == false) + { + var border = GetDrawingBorder(); + AddDeclaration("border", border); + } + + return declarations; + } + + private string GetDrawingBorder() + { + Color color = _border.Fill.Color; + if (color.IsEmpty) return ""; + string lineStyle = $"{_border.Width}px"; + + switch (_border.LineStyle.Value) + { + case eLineStyle.Solid: + lineStyle += " solid"; + break; + case eLineStyle.Dash: + case eLineStyle.LongDashDot: + case eLineStyle.LongDashDotDot: + case eLineStyle.SystemDash: + case eLineStyle.SystemDashDot: + case eLineStyle.SystemDashDotDot: + lineStyle += $" dashed"; + break; + case eLineStyle.Dot: + lineStyle += $" dot"; + break; + } + + lineStyle += " #" + color.ToArgb().ToString("x8").Substring(2); + return lineStyle; + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/Translators/CssFillTranslator.cs b/src/EPPlus/Export/HtmlExport/Translators/CssFillTranslator.cs index ddd6d19d25..3da86afff0 100644 --- a/src/EPPlus/Export/HtmlExport/Translators/CssFillTranslator.cs +++ b/src/EPPlus/Export/HtmlExport/Translators/CssFillTranslator.cs @@ -27,10 +27,20 @@ internal class CssFillTranslator : TranslatorBase { ExcelTheme _theme; IFill _fill; + bool _usePresentationName = false; - internal CssFillTranslator(IFill fill) + string presentationName = "fill"; + + string bgName = "background-color"; + + internal CssFillTranslator(IFill fill, bool usePresentationName = false) { _fill = fill; + _usePresentationName = usePresentationName; + if(usePresentationName) + { + bgName = presentationName; + } } internal override List GenerateDeclarationList(TranslatorContext context) @@ -50,7 +60,7 @@ internal override List GenerateDeclarationList(TranslatorContext co var bc = _fill.GetBackgroundColor(_theme) ?? "#0"; if (string.IsNullOrEmpty(bc) == false) { - AddDeclaration("background-color", bc); + AddDeclaration(bgName, bc); } } else if(_fill.PatternType == ExcelFillStyle.None) @@ -58,7 +68,7 @@ internal override List GenerateDeclarationList(TranslatorContext co var fc = _fill.GetPatternColor(_theme); if (string.IsNullOrEmpty(fc) == false) { - AddDeclaration("background-color", fc); + AddDeclaration(bgName, fc); } } else diff --git a/src/EPPlus/Export/HtmlExport/Translators/CssImageTranslator.cs b/src/EPPlus/Export/HtmlExport/Translators/CssImageTranslator.cs index 8eff1db2cc..0fc2ec21ec 100644 --- a/src/EPPlus/Export/HtmlExport/Translators/CssImageTranslator.cs +++ b/src/EPPlus/Export/HtmlExport/Translators/CssImageTranslator.cs @@ -12,15 +12,17 @@ Date Author Change *************************************************************************************************/ using OfficeOpenXml.Drawing; using OfficeOpenXml.Export.HtmlExport.CssCollections; +using System; using System.Collections.Generic; namespace OfficeOpenXml.Export.HtmlExport.Translators { internal class CssImageTranslator : TranslatorBase { - HtmlImage _p; + HtmlDrawing _p; string _encodedImage; internal ePictureType? type; + bool isDrawing = false; public CssImageTranslator(HtmlImage p) { @@ -28,6 +30,16 @@ public CssImageTranslator(HtmlImage p) _encodedImage = ImageEncoder.EncodeImage(p, out type); } + public CssImageTranslator(HtmlSvgDrawing d) + { + _p = d; + var charArr = d.Drawing.ToSvg().ToCharArray(); + var byteArr = System.Text.Encoding.UTF8.GetBytes(charArr); + _encodedImage = Convert.ToBase64String(byteArr); + type = ePictureType.Svg; + isDrawing = true; + } + internal override List GenerateDeclarationList(TranslatorContext context) { AddDeclaration("content", $"url('data:{GetContentType(type.Value)};base64,{_encodedImage}')"); @@ -37,6 +49,11 @@ internal override List GenerateDeclarationList(TranslatorContext co AddDeclaration("position", $"{context.Pictures.Position.ToString().ToLower()}"); } + if(isDrawing && context.Drawings.Position != ePicturePosition.DontSet) + { + AddDeclaration("position", $"{context.Drawings.Position.ToString().ToLower()}"); + } + if (_p.FromColumnOff != 0 && context.Pictures.AddMarginLeft) { var leftOffset = _p.FromColumnOff / ExcelPicture.EMU_PER_PIXEL; diff --git a/src/EPPlus/Export/HtmlExport/Translators/CssStrokeTranslator.cs b/src/EPPlus/Export/HtmlExport/Translators/CssStrokeTranslator.cs new file mode 100644 index 0000000000..8ea8396950 --- /dev/null +++ b/src/EPPlus/Export/HtmlExport/Translators/CssStrokeTranslator.cs @@ -0,0 +1,33 @@ +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.Export.HtmlExport.CssCollections; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Export.HtmlExport.Translators +{ + internal class CssStrokeTranslator : TranslatorBase + { + IDrawingBorder _drawingBorder; + ExcelTheme _theme; + + public CssStrokeTranslator(IDrawingBorder drawingBorder) + { + _drawingBorder = drawingBorder; + } + + internal override List GenerateDeclarationList(TranslatorContext context) + { + var borderExclude = context.Exclude.Border; + _theme = context.Theme; + + if(_drawingBorder.Stroke.HasValue && _drawingBorder.Stroke.PatternType == Style.ExcelFillStyle.Solid) + { + AddDeclaration($"stroke", _drawingBorder.Stroke.GetBackgroundColor(_theme)); + } + return declarations; + } + } +} diff --git a/src/EPPlus/Export/HtmlExport/Translators/TranslatorContext.cs b/src/EPPlus/Export/HtmlExport/Translators/TranslatorContext.cs index 8145d29490..92e90b0b6b 100644 --- a/src/EPPlus/Export/HtmlExport/Translators/TranslatorContext.cs +++ b/src/EPPlus/Export/HtmlExport/Translators/TranslatorContext.cs @@ -34,6 +34,7 @@ internal class TranslatorContext internal CssExclude Exclude; internal CssExportSettings Settings; internal HtmlPictureSettings Pictures; + internal HtmlDrawingSettings Drawings; private TranslatorBase strategy; @@ -42,18 +43,25 @@ internal class TranslatorContext internal HashSet AddedIcons = new HashSet(); + public TranslatorContext(CssExportSettings settings) + { + Settings = settings; + Exclude = new CssExclude(); + } public TranslatorContext(HtmlRangeExportSettings settings) { Exclude = settings.Css.CssExclude; Settings = settings.Css; Pictures = settings.Pictures; + Drawings = settings.Drawings; } public TranslatorContext(HtmlTableExportSettings settings, CssExclude exclude) { Settings = settings.Css; Pictures = settings.Pictures; + Drawings = settings.Drawings; Exclude = exclude; } diff --git a/src/EPPlus/Export/PdfExport/Data/PageData.cs b/src/EPPlus/Export/PdfExport/Data/PageData.cs new file mode 100644 index 0000000000..6a7d8c510c --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PageData.cs @@ -0,0 +1,58 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Export.PdfExport.TextMapping; +using OfficeOpenXml.Style; +using System.Collections.Generic; +using EPPlus.Export.Pdf.Layout; +using OfficeOpenXml.Export.PdfExport.Layout; + + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + internal struct Page + { + public int FromRow; + public int FromColumn; + public int ToRow; + public int ToColumn; + public bool HasPrintTitle; + public double PrintTitleWidth; + public double PrintTitleHeight; + public PdfCellCollection Map; + public PdfHeaderFooterCollection HeaderFooters; + public Dictionary MergedCells; + public List PrintTitleCells; + public List PrintTitleGridLines; + public List PrintTitleHeadings; + public List SpillCells; + public List PrintTitleBorders; + public double[] RowHeights; + public double HeadingWidth; + public double HeadingHeight; + } + + internal struct Pages + { + public Page[] Page; + public int Width; + public int Height; + public bool IsCommentsPage; + public string HeadingFontName; + public float HeadingFontSize; + public ExcelFill HeadingFill; + public int Count + { + get { return Width * Height; } + } + } +} diff --git a/src/EPPlus/Export/PdfExport/Data/PdfCell.cs b/src/EPPlus/Export/PdfExport/Data/PdfCell.cs new file mode 100644 index 0000000000..ed31455598 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PdfCell.cs @@ -0,0 +1,24 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Layout; + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + internal class PdfCell : PdfCellBase + { + public PdfCellStyle CellStyle; + public bool Merged; + public PdfCell Main; + public ExcelAddressBase MergedAddress; + } +} diff --git a/src/EPPlus/Export/PdfExport/Data/PdfCellCollection.cs b/src/EPPlus/Export/PdfExport/Data/PdfCellCollection.cs new file mode 100644 index 0000000000..6fda2ed901 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PdfCellCollection.cs @@ -0,0 +1,68 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + internal class PdfCellCollection + { + public readonly int FromRow; + public readonly int FromColumn; + public readonly int ToRow; + public readonly int ToColumn; + + private PdfCell[,] Cells; + + public PdfCellCollection(int fromRow, int toRow, int fromColumn, int toColumn) + { + if(fromRow > toRow) throw new ArgumentOutOfRangeException("Invalid row range. toRow must be equal or greater than fromRow"); + if(fromColumn > toColumn) throw new ArgumentOutOfRangeException("Invalid column range. toColumn must be equal or greater than fromColumn"); + FromRow = fromRow; + FromColumn = fromColumn; + ToRow = toRow; + ToColumn = toColumn; + int x = toRow - fromRow + 1; + int y = toColumn - fromColumn + 1; + + Cells = new PdfCell[x, y]; + } + + public PdfCell this[int row, int column] + { + get + { + var r = row - FromRow; + var c = column - FromColumn; + if (r < 0 || c < 0 || r >= Cells.GetLength(0) || c >= Cells.GetLength(1)) + { + return null; + } + return Cells[r, c]; + } + set + { + Cells[row - FromRow, column - FromColumn] = value; + } + } + + public PdfCell GetInternal(int row, int column) + { + return Cells[row, column]; + } + + public void SetInternal(int row, int column, PdfCell value) + { + Cells[row, column] = value; + } + } +} diff --git a/src/EPPlus/Export/PdfExport/Data/PdfCellStyle.cs b/src/EPPlus/Export/PdfExport/Data/PdfCellStyle.cs new file mode 100644 index 0000000000..f5981d231a --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PdfCellStyle.cs @@ -0,0 +1,51 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.Dxf; + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + /// + /// Holds the styles for the cell. + /// xf styles is the base style and dxf styles is an override(sort of) that can come from tables or conditional formatting. + /// They are used in the following priority: + /// 1. xf style that is not default + /// 2. dxf style if it exsist + /// 3. deault xf style + /// + internal class PdfCellStyle + { + //Fill + internal ExcelFill xfFill { get; set; } + internal ExcelDxfFill dxfFill { get; set; } + + //Borders + internal ExcelBorderItem xfTop { get; set; } + internal ExcelBorderItem xfBottom { get; set; } + internal ExcelBorderItem xfLeft { get; set; } + internal ExcelBorderItem xfRight { get; set; } + internal bool DiagonalUp { get; set; } + internal bool DiagonalDown { get; set; } + internal ExcelBorderItem Diagonal { get; set; } + internal ExcelDxfBorderItem dxfTop { get; set; } + internal ExcelDxfBorderItem dxfBottom { get; set; } + internal ExcelDxfBorderItem dxfLeft { get; set; } + internal ExcelDxfBorderItem dxfRight { get; set; } + internal ExcelDxfBorderItem dxfHorizontal { get; set; } + internal ExcelDxfBorderItem dxfVertical { get; set; } + + //Fonts + internal ExcelFont xfFont { get; set; } + internal ExcelDxfFontBase dxfFont { get; set; } + } +} diff --git a/src/EPPlus/Export/PdfExport/Data/PdfRange.cs b/src/EPPlus/Export/PdfExport/Data/PdfRange.cs new file mode 100644 index 0000000000..74206fe8e5 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PdfRange.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System.Collections.Generic; + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + internal struct RowHeight + { + public double Height; + public bool UsesDefaultValue; + } + + internal struct PdfRange + { + public List RowHeights = new List(); + public List ColWidths = new List(); + public double TotalHeight; + public double TotalWidth; + public double AdditionalHeight; + public double AdditionalWidth; + public double PrintTitleHeight; + public double PrintTitleWidth; + public int PrintTitleRowTo = -1; + public int PrintTitleColTo = -1; + + public ExcelRangeBase Range { get; set; } + public bool ExtendColumns { get; set; } + public PdfCellCollection Map { get; set; } + + public PdfRange(ExcelRangeBase range, bool extendColumns) + { + Range = range; + ExtendColumns = extendColumns; + } + } +} diff --git a/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs b/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs new file mode 100644 index 0000000000..9261792bac --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs @@ -0,0 +1,70 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.TextShaping; +using OfficeOpenXml.Export.PdfExport.TextMapping; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Style.XmlAccess; +using System.Collections.Generic; + +namespace OfficeOpenXml.Export.PdfExport.Data +{ + internal class PdfWorksheet + { + public Dictionary CommentsAndNotesCollections = new Dictionary(); + + public List Ranges = null; //Rename this + public PdfRange CommentsAndNotes; + public PdfHeaderFooterCollection HeaderFooters = null; + public double ZeroCharWidth; + public int ToRow; + public int PrintTitleRowFrom = -1; + public int PrintTitleRowTo = -1; + public int PrintTitleColFrom = -1; + public int PrintTitleColTo = -1; + + //EPPlus references + public ExcelWorksheet Worksheet { get; set; } + public ExcelWorksheet CommentsAndNotesSheet { get; set; } + public ExcelNamedStyleXml NormalStyle { get { return Worksheet.Workbook.Styles.GetNormalStyle(); } } + public FontSubFamily GetSubFamilyFromNormalStyle //move this to a helper class or something. + { + get + { + var nsf = NormalStyle.Style.Font; + var SubFamily = FontSubFamily.Regular; + if (nsf.Bold) + { + SubFamily = FontSubFamily.Bold; + if (nsf.Italic) + { + SubFamily = FontSubFamily.BoldItalic; + } + } + else if (nsf.Italic) + { + SubFamily = FontSubFamily.Italic; + } + return SubFamily; + } + } + + public static double GetThemeFont0Width(ExcelWorksheet ws) + { + var ns = ws.Workbook.Styles.GetNormalStyle(); + TextShaper shaper = OpenTypeFonts.GetTextShaper(ns.Style.Font.Name, FontSubFamily.Regular); + var shapedText = shaper.ShapeLight("0"); + return shapedText.GetWidthInPoints(ns.Style.Font.Size); + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Export/PdfExport/Layout/PdfGridlinesLayout.cs b/src/EPPlus/Export/PdfExport/Layout/PdfGridlinesLayout.cs new file mode 100644 index 0000000000..d2f9f50e7d --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Layout/PdfGridlinesLayout.cs @@ -0,0 +1,373 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Settings; +using OfficeOpenXml.Export.PdfExport.Data; +using EPPlus.Export.Pdf.Layout; +using OfficeOpenXml.Style; + +namespace OfficeOpenXml.Export.PdfExport.Layout +{ + internal class PdfGridlinesLayout + { + //------------------------------------------------------------------------------------------ + // Gridline generation + // ----------------------------------------------------------------------------------------- + + /// + /// Populates .GridLines and .BorderLines for one page. + /// + /// Algorithm: + /// 1. Precompute column X positions and row Y positions from the page map / row-height array. + /// 2. Walk every cell and mark which vertical column-gaps are suppressed by text spill. + /// Spill direction depends on horizontal alignment; spill stops when a destination cell + /// has content. Multi-column spill is handled by walking until either the text runs + /// out or a non-empty cell is found. + /// 3. Emit vertical gridline segments: for each column gap, accumulate contiguous rows + /// that are not blocked by spill, a cell border, or a merged cell spanning the gap. + /// 4. Emit horizontal gridline segments: for each row gap, accumulate contiguous columns + /// that are not blocked by a cell border or a merged cell spanning the gap. + /// 5. Add the four outer-frame lines to BorderLines. + /// + public static void AddGridLines(PdfPageSettings pageSettings, Page page, PdfPageLayout pageLayout, bool borderOnly = false) + { + int rowCount = page.ToRow - page.FromRow + 1; + int colCount = page.ToColumn - page.FromColumn + 1; + + if (rowCount <= 0 || colCount <= 0) return; + + // --- 1. Position arrays --------------------------------------------------------------- + + // colX[ci] = X of left edge of column ci (0-based within page). + // colX[colCount] = X of right edge of last column. + var colX = new double[colCount + 1]; + colX[0] = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth; + for (int ci = 0; ci < colCount; ci++) + { + var cell = page.Map[page.FromRow, page.FromColumn + ci]; + colX[ci + 1] = colX[ci] + (cell?.ColumnWidth ?? 0d); + } + + // rowY[ri] = Y of top edge of row ri (0-based within page). + // rowY[rowCount] = Y of bottom edge of last row. + // Y decreases downward (PDF coordinate system used throughout GetCatalog). + var rowY = new double[rowCount + 1]; + rowY[0] = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight; + + for (int ri = 0; ri < rowCount; ri++) + { + rowY[ri + 1] = rowY[ri] - page.RowHeights[ri]; + } + + // --- 5. Outer frame ------------------------------------------------------------------ + // Always computed so BorderLines is available for margin clipping regardless of + // whether ShowGridLines is on. When borderOnly is true we stop here. + + double frameLeft = pageSettings.ContentBounds.Left; //colX[0]; + double frameRight = colX[colCount]; + double frameTop = pageSettings.ContentBounds.Top; //rowY[0]; + double frameBottom = rowY[rowCount]; + + pageLayout.BorderLines.Add(new GridLine(frameLeft, frameTop, frameRight, frameTop)); + pageLayout.BorderLines.Add(new GridLine(frameLeft, frameBottom, frameRight, frameBottom)); + pageLayout.BorderLines.Add(new GridLine(frameLeft, frameTop, frameLeft, frameBottom)); + pageLayout.BorderLines.Add(new GridLine(frameRight, frameTop, frameRight, frameBottom)); + + if (borderOnly) return; + + // --- 2. Text-spill mask --------------------------------------------------------------- + + // spillBlocked[ri, gi] = true means the vertical line at colX[gi+1] for row ri + // must be suppressed because cell text from this row spills across that gap. + // gi ranges 0 .. colCount-2. + var spillBlocked = new bool[rowCount, colCount - 1]; + + for (int ri = 0; ri < rowCount; ri++) + { + int row = page.FromRow + ri; + for (int ci = 0; ci < colCount; ci++) + { + int col = page.FromColumn + ci; + var cell = page.Map[row, col]; + + if (cell == null || cell.Hidden || (cell.ContentAligmnet != null && cell.ContentAligmnet.WrapText)) continue; + // Merged cells never spill — their text is clipped to the merged region. + // The vertical lines around the merge are handled by MergedAcross checks below. + if (cell.Merged) continue; + + double spill = cell.TotalTextLength - cell.ColumnWidth; + if (spill <= 0d) continue; + + var halign = cell.ContentAligmnet.HorizontalAlignment; + + // Right spill — Left / General alignment. + if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left || + halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General) + { + MarkSpillRight(page, ri, ci, colCount, colX, spill, spillBlocked); + + } + + // Left spill — Right alignment. + else if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) + { + MarkSpillLeft(page, ri, ci, colX, spill, spillBlocked); + } + // Both directions — Center alignment, half the excess each way. + else if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) + { + double halfSpill = spill / 2d; + MarkSpillRight(page, ri, ci, colCount, colX, halfSpill, spillBlocked); + MarkSpillLeft(page, ri, ci, colX, halfSpill, spillBlocked); + + } + } + } + + // --- 3. Vertical gridlines (one per internal column gap) ----------------------------- + + for (int gi = 0; gi < colCount - 1; gi++) + { + double x = colX[gi + 1]; + int leftCol = page.FromColumn + gi; + int rightCol = leftCol + 1; + + double? runStart = null; + double runEnd = 0d; + + for (int ri = 0; ri < rowCount; ri++) + { + int row = page.FromRow + ri; + + // Hidden rows have zero height — no segment to draw. + if (page.RowHeights[ri] == 0d) + { + FlushVertical(pageLayout, x, ref runStart, runEnd); + continue; + } + + var leftCell = page.Map[row, leftCol]; + var rightCell = page.Map[row, rightCol]; + + bool blocked = + spillBlocked[ri, gi] || + MergedAcross(leftCell, leftCol) || // left cell's merge extends right past this gap + MergedAcross(rightCell, rightCol, fromLeft: true) || // right cell's merge came from the left + HasRightBorder(leftCell) || + HasLeftBorder(rightCell); + + if (!blocked) + { + if (runStart == null) runStart = rowY[ri]; + runEnd = rowY[ri + 1]; + } + else + { + FlushVertical(pageLayout, x, ref runStart, runEnd); + } + } + FlushVertical(pageLayout, x, ref runStart, runEnd); + } + + // --- 4. Horizontal gridlines (one per internal row gap) ------------------------------ + + for (int ri = 0; ri < rowCount - 1; ri++) + { + double y = rowY[ri + 1]; + int topRow = page.FromRow + ri; + int bottomRow = topRow + 1; + + double? runStart = null; + double runEnd = 0d; + + for (int ci = 0; ci < colCount; ci++) + { + int col = page.FromColumn + ci; + + // Hidden columns have zero width — no segment to draw. + if (colX[ci + 1] - colX[ci] == 0d) + { + FlushHorizontal(pageLayout, y, ref runStart, runEnd); + continue; + } + + var topCell = page.Map[topRow, col]; + var bottomCell = page.Map[bottomRow, col]; + + bool blocked = + MergedDown(topCell, topRow) || // top cell's merge extends down past this gap + MergedDown(bottomCell, bottomRow, fromAbove: true) || // bottom cell's merge came from above + HasBottomBorder(topCell) || + HasTopBorder(bottomCell); + + if (!blocked) + { + if (runStart == null) runStart = colX[ci]; + runEnd = colX[ci + 1]; + } + else + { + FlushHorizontal(pageLayout, y, ref runStart, runEnd); + } + } + FlushHorizontal(pageLayout, y, ref runStart, runEnd); + } + } + + // ---- Spill helpers ---------------------------------------------------------------------- + + /// + /// Marks column gaps to the right of column as spill-blocked for + /// row , until the spill budget runs out or a non-empty cell stops it. + /// + private static void MarkSpillRight( + Page page, int ri, int ci, int colCount, + double[] colX, double spill, bool[,] spillBlocked) + { + int row = page.FromRow + ri; + // Walk gaps gi = ci, ci+1, ... (gap gi lies between column gi and column gi+1). + for (int gi = ci; gi < colCount - 1; gi++) + { + // The cell immediately to the right of this gap stops the spill if it has text. + var rightCell = page.Map[row, page.FromColumn + gi + 1]; + if (rightCell != null && !string.IsNullOrEmpty(rightCell.Text)) break; + + // Distance from the right edge of the source cell to this gap. + double distToGap = colX[gi + 1] - colX[ci + 1]; + if (spill > distToGap) + spillBlocked[ri, gi] = true; + else + break; + } + } + + /// + /// Marks column gaps to the left of column as spill-blocked for + /// row , until the spill budget runs out or a non-empty cell stops it. + /// + private static void MarkSpillLeft( + Page page, int ri, int ci, + double[] colX, double spill, bool[,] spillBlocked) + { + int row = page.FromRow + ri; + // Walk gaps gi = ci-1, ci-2, ... (gap gi lies between column gi and column gi+1). + for (int gi = ci - 1; gi >= 0; gi--) + { + // The cell immediately to the left of this gap stops the spill if it has text. + var leftCell = page.Map[row, page.FromColumn + gi]; + if (leftCell != null && !string.IsNullOrEmpty(leftCell.Text)) break; + + // Distance from the left edge of the source cell to this gap. + double distToGap = colX[ci] - colX[gi + 1]; + if (spill > distToGap) + spillBlocked[ri, gi] = true; + else + break; + } + } + + // ---- Run-flush helpers ------------------------------------------------------------------ + + private static void FlushVertical(PdfPageLayout layout, double x, ref double? runStart, double runEnd) + { + if (runStart == null) return; + layout.GridLines.Add(new GridLine(x, runStart.Value, x, runEnd)); + runStart = null; + } + + private static void FlushHorizontal(PdfPageLayout layout, double y, ref double? runStart, double runEnd) + { + if (runStart == null) return; + layout.GridLines.Add(new GridLine(runStart.Value, y, runEnd, y)); + runStart = null; + } + + // ---- Merge-span helpers ----------------------------------------------------------------- + + /// + /// Returns true when is part of a merged region that spans across + /// the vertical gap adjacent to . + /// + /// = false (default): cell is the LEFT neighbour of the gap — + /// block if the merge extends to the right (toCol > col). + /// + /// + /// = true: cell is the RIGHT neighbour of the gap — + /// block if the merge started to the left (fromCol < col). + /// + /// + private static bool MergedAcross(PdfCell cell, int col, bool fromLeft = false) + { + if (cell == null || !cell.Merged || cell.MergedAddress == null) return false; + return fromLeft + ? cell.MergedAddress._fromCol < col + : cell.MergedAddress._toCol > col; + } + + /// + /// Returns true when is part of a merged region that spans across + /// the horizontal gap adjacent to . + /// + /// = false (default): cell is the TOP neighbour of the gap — + /// block if the merge extends downward (toRow > row). + /// + /// + /// = true: cell is the BOTTOM neighbour of the gap — + /// block if the merge started above (fromRow < row). + /// + /// + private static bool MergedDown(PdfCell cell, int row, bool fromAbove = false) + { + if (cell == null || !cell.Merged || cell.MergedAddress == null) return false; + return fromAbove + ? cell.MergedAddress._fromRow < row + : cell.MergedAddress._toRow > row; + } + + // ---- Border presence helpers ------------------------------------------------------------ + // For merged cells, use the main cell's style (which holds the region's outer borders). + + private static bool HasRightBorder(PdfCell cell) + { + var cs = (cell?.Merged == true && cell.Main != null) ? cell.Main.CellStyle : cell?.CellStyle; + if (cs == null) return false; + return (cs.xfRight != null && cs.xfRight.Style != ExcelBorderStyle.None) || + (cs.dxfRight?.HasValue ?? false); + + } + + private static bool HasLeftBorder(PdfCell cell) + { + var cs = (cell?.Merged == true && cell.Main != null) ? cell.Main.CellStyle : cell?.CellStyle; + if (cs == null) return false; + return (cs.xfLeft != null && cs.xfLeft.Style != ExcelBorderStyle.None) || + (cs.dxfLeft?.HasValue ?? false); + } + + private static bool HasTopBorder(PdfCell cell) + { + var cs = (cell?.Merged == true && cell.Main != null) ? cell.Main.CellStyle : cell?.CellStyle; + if (cs == null) return false; + return (cs.xfTop != null && cs.xfTop.Style != ExcelBorderStyle.None) || + (cs.dxfTop?.HasValue ?? false); + } + + private static bool HasBottomBorder(PdfCell cell) + { + var cs = (cell?.Merged == true && cell.Main != null) ? cell.Main.CellStyle : cell?.CellStyle; + if (cs == null) return false; + return (cs.xfBottom != null && cs.xfBottom.Style != ExcelBorderStyle.None) || + (cs.dxfBottom?.HasValue ?? false); + } + + } +} diff --git a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs new file mode 100644 index 0000000000..b5b9b3f719 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs @@ -0,0 +1,1595 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Helpers; +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics; +using OfficeOpenXml.Export.PdfExport.Data; +using OfficeOpenXml.Export.PdfExport.TextShaping; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Style; +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace OfficeOpenXml.Export.PdfExport.Layout +{ + internal struct PrintTitleCellDraw + { + public PdfCell Cell; + public double X; + public double Y; + public double Width; + public double Height; + public double ClipX; // text clip (spill bound) + public double ClipY; + public double ClipWidth; + public double ClipHeight; + } + + internal struct PrintTitleHeadingDraw + { + public bool IsRow; // true = row-number heading (left strip); false = column-letter (top strip) + public int Index; // original absolute row/column index — the label source + public double X; + public double Y; + public double Width; + public double Height; + } + + internal struct SpillCellDraw + { + public PdfCell Cell; + public double X, Y, Width, Height; // source cell's true position (off-window) + public double ClipX, ClipY, ClipWidth, ClipHeight; // visible slice on this page + public bool IsPrintTitle; + } + + internal class PdfLayout + { + private const double rowHeadingWith1CharWidth = 18d; + + public static Transform GetLayout(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfWorksheet[] pdfSheets) + { + var PagesCollection = GetPages(pageSettings, pdfSheets); + var Catalog = GetCatalog(pageSettings, dictionaries, PagesCollection); + return Catalog; + } + + internal static Transform GetCatalog(PdfPageSettings pageSettings, PdfDictionaries dictionaries, List pdfPages) + { + Transform Catalog = new Transform(0d, 0d, 0d, 0d); + int totalPages = GetTotalPages(pdfPages); + for (int i = 0; i < pdfPages.Count; i++) + { + var pages = pdfPages[i].Page; + int pageNumber = pageSettings.FirstPageNumber; + for (int j = 0; j < pages.Length; j++) + { + var page = pages[j]; + PdfPageLayout pageLayout = new PdfPageLayout(0d, 0d, 0d, 0d); + pageLayout.isCommentsPage = pdfPages[i].IsCommentsPage; + pageLayout.HeadingWidth = page.HeadingWidth; + pageLayout.HeadingHeight = page.HeadingHeight; + pageLayout.PrintTitleWidth = page.PrintTitleWidth; + pageLayout.PrintTitleHeight = page.PrintTitleHeight; + var drawnMergedCells = new HashSet(); + double contentStartX = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth; + double contentStartY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight; + if (pageSettings.ShowHeadings && !pdfPages[i].IsCommentsPage) + { + AddHeadingCells(pageSettings, dictionaries, page, pageLayout, contentStartX, contentStartY, page.HeadingWidth, page.HeadingHeight, pdfPages[i].HeadingFontName, pdfPages[i].HeadingFontSize, pdfPages[i].HeadingFill); + AddPrintTitleHeadings(pageSettings, dictionaries, page, pageLayout, pdfPages[i].HeadingFontName, pdfPages[i].HeadingFontSize, pdfPages[i].HeadingFill); + AddSpillCells(pageSettings, dictionaries, page, pageLayout); + } + AddPrintTitleCells(pageSettings, dictionaries, page, pageLayout); + double y = contentStartY; + double x = contentStartX; + for (int row = pages[j].FromRow; row <= pages[j].ToRow; row++) + { + double rowHeight = pages[j].RowHeights[row - pages[j].FromRow]; + for (int col = pages[j].FromColumn; col <= pages[j].ToColumn; col++) + { + var map = pages[j].Map[row, col]; + MergedCellDrawInfo info = new MergedCellDrawInfo(); + //Merged Cell + if (map.Merged) + { + string key = map.MergedAddress.Address; + if (!drawnMergedCells.Contains(key) && + pages[j].MergedCells.TryGetValue(key, out info)) + { + //Fill + var cellStyle = map.Main?.CellStyle ?? map.CellStyle; + var fill = new PdfCellLayout(info.X, info.Y, info.Width, info.Height); + SetFill(dictionaries, cellStyle, map.Text, fill); + fill.Name = map.Name; + fill.UpdateShadingPositionMatrix(pageSettings); + pageLayout.AddChild(fill); + //Text + var sourceMap = (map.TextLines != null && map.TextLines.Count > 0) ? map : (map.Main != null && map.Main.TextLines != null && map.Main.TextLines.Count > 0) ? map.Main : null; + if (sourceMap != null) + { + var text = new PdfCellContentLayout(pageSettings, dictionaries, sourceMap, info, info.X, info.Y, info.Width, info.Height); + text.Name = map.Name; + text.GidsAndCharMap(dictionaries); + text.SetupClipping(info.X, info.Y, info.Width, info.Height); + pageLayout.AddChild(text); + } + if (map.Main != null) // map.Main != null → this is NOT the top-left cell + { + var mergeMainStyle = map.Main.CellStyle; + if (HasDiagonalBorder(mergeMainStyle)) + { + var diagBorder = new PdfCellBorderLayout( + isMerged: false, // use X/Y/W/H path in renderer, not info.* + corners: MergedCellCorners.All, + info: info, + x: info.X, // virtual full-merge top-left X + y: info.Y, // virtual full-merge top Y + width: info.Width, // full merge width + height: info.Height); // full merge height + SetBorderStyle(mergeMainStyle, diagBorder); + diagBorder.Name = map.Name; + // Suppress edge borders — this layout exists only for the diagonal + diagBorder.BorderData.Top.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + diagBorder.BorderData.Bottom.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + diagBorder.BorderData.Left.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + diagBorder.BorderData.Right.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + pageLayout.AddChild(diagBorder); + } + } + drawnMergedCells.Add(key); + } + } + else + { + //Fill + var fill = new PdfCellLayout(x, y, map.ColumnWidth, rowHeight); + SetFill(dictionaries, map.CellStyle, map.Text, fill); + fill.UpdateShadingPositionMatrix(pageSettings); + fill.Name = map.Name; + pageLayout.AddChild(fill); + //Text + if (map.TextLines != null && map.TextLines.Count > 0) + { + var text = new PdfCellContentLayout(pageSettings, dictionaries, map, info, x, y, map.ColumnWidth, rowHeight); + text.Name = map.Name; + text.GidsAndCharMap(dictionaries); + if (NeedsClipping(map, pages[j], row, col)) + text.SetupClipping(x, y, map.ColumnWidth, rowHeight); + pageLayout.AddChild(text); + } + } + //Border + var borderStyle = (map.Merged && map.Main != null) ? map.Main.CellStyle : map.CellStyle; + if (HasBorder(map.CellStyle)) + { + var border = new PdfCellBorderLayout(map.Merged, GetCorners(map.MergedAddress, row, col), info, x, y, map.ColumnWidth, rowHeight); + SetBorderStyle(map.CellStyle, border); + border.Name = map.Name; + if (map.Merged && map.MergedAddress != null) + { + var addr = map.MergedAddress; + if (row != addr.Start.Row) border.BorderData.Top.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + if (row != addr.End.Row) border.BorderData.Bottom.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + if (col != addr.Start.Column) border.BorderData.Left.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + if (col != addr.End.Column) border.BorderData.Right.BorderStyle = (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)ExcelBorderStyle.None; + } + pageLayout.AddChild(border); + } + x += map.ColumnWidth; + } + y -= rowHeight; + x = contentStartX; //pageSettings.ContentBounds.Left; + } + if (page.HeaderFooters != null) + { + bool isVeryFirstPage = (i == 0 && j == 0); + var hfType = isVeryFirstPage ? HeaderFooterType.First : (pageNumber % 2 == 0 ? HeaderFooterType.Even : HeaderFooterType.Odd); + var leftH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Left); + if (leftH != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, leftH, pageNumber, totalPages); + var ascent = leftH.Content.TextLines[0].LargestAscent; + var hfx = pageSettings.Margins.LeftPu; + var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; + var text = new PdfCellContentLayout(pageSettings, dictionaries, leftH, hfx, hfy, 0, 0); + text.Name = "LeftHeader"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + var centerH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Center); + if (centerH != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, centerH, pageNumber, totalPages); + var ascent = centerH.Content.TextLines[0].LargestAscent; + var hfx = pageSettings.Margins.LeftPu; + var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; + var hfWidth = pageSettings.PageSize.WidthPu - pageSettings.Margins.LeftPu - pageSettings.Margins.RightPu; + var text = new PdfCellContentLayout(pageSettings, dictionaries, centerH, hfx, hfy, hfWidth, 0); + text.Name = "CenterHeader"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + var rightH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Right); + if (rightH != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, rightH, pageNumber, totalPages); + var ascent = rightH.Content.TextLines[0].LargestAscent; + var hfx = pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu; + var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; + var text = new PdfCellContentLayout(pageSettings, dictionaries, rightH, hfx, hfy, 0, 0); + text.Name = "RightHeader"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + var leftF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Left); + if (leftF != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, leftF, pageNumber, totalPages); + int last = leftF.Content.TextLines.Count - 1; + var descent = leftF.Content.TextLines[last].LargestDescent; + var hfx = pageSettings.Margins.LeftPu; + var hfy = pageSettings.Margins.FooterPu + descent; + var text = new PdfCellContentLayout(pageSettings, dictionaries, leftF, hfx, hfy, 0, 0); + text.Name = "LeftFooter"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + var centerF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Center); + if (centerF != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, centerF, pageNumber, totalPages); + int last = centerF.Content.TextLines.Count - 1; + var descent = centerF.Content.TextLines[last].LargestDescent; + var hfx = pageSettings.PageSize.WidthPu / 2d; + var hfy = pageSettings.Margins.FooterPu + descent; + var text = new PdfCellContentLayout(pageSettings, dictionaries, centerF, hfx, hfy, 0, 0); + text.Name = "CenterFooter"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + var rightF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Right); + if (rightF != null) + { + SubstitutePageNumbers(pageSettings, dictionaries, rightF, pageNumber, totalPages); + int last = rightF.Content.TextLines.Count - 1; + var descent = rightF.Content.TextLines[last].LargestDescent; + var hfx = pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu; + var hfy = pageSettings.Margins.FooterPu + descent; + var text = new PdfCellContentLayout(pageSettings, dictionaries, rightF, hfx, hfy, 0, 0); + text.Name = "RightFooter"; + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + } + PdfGridlinesLayout.AddGridLines(pageSettings, pages[j], pageLayout, borderOnly: !pageSettings.ShowGridLines || pdfPages[i].IsCommentsPage); + pageLayout.ChildObjects.Sort((a, b) => + { + int cmp = a.Z.CompareTo(b.Z); + if (cmp == 0) + return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase); + return cmp; + }); + pageNumber++; + Catalog.AddChild(pageLayout); + } + } + return Catalog; + } + + private static void SetFill(PdfDictionaries dictionaries, PdfCellStyle cellStyle, string text, PdfCellLayout fill) + { + var xfFill = cellStyle.xfFill; + var dxfFill = cellStyle.dxfFill; + if (dxfFill != null && xfFill.IsEmpty()) + { + var patternStyle = dxfFill.PatternType != null ? (ExcelFillStyle)dxfFill.PatternType : ExcelFillStyle.Solid; + if (patternStyle == ExcelFillStyle.Solid) + { + fill.SetFill( PdfColor.SetColorFromHex(dxfFill.BackgroundColor.LookupColor())); + } + else if (patternStyle != ExcelFillStyle.None) + { + var bkgc = PdfColor.SetColorFromHex(dxfFill.PatternColor.Color == null ? "#FFFFFFFF" : dxfFill.PatternColor.LookupColor()); + var patc = PdfColor.SetColorFromHex(dxfFill.BackgroundColor.LookupColor()); + fill.SetPattern(dictionaries, (EPPlus.Export.Pdf.Enums.ExcelFillStyle)patternStyle, bkgc, patc); + } + else if (dxfFill.Gradient != null) + { + var gradientType = dxfFill.Gradient.GradientType == null ? ExcelFillGradientType.None : (ExcelFillGradientType)dxfFill.Gradient.GradientType; + var color1 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[0].Color.LookupColor()); + var color2 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[1].Color.LookupColor()); + var color3 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[2].Color.LookupColor()); + var degree = dxfFill.Gradient.Degree == null ? 0 : (double)dxfFill.Gradient.Degree; + var top = dxfFill.Gradient.Top == null ? 0 : (double)dxfFill.Gradient.Top; + var bottom = dxfFill.Gradient.Bottom == null ? 0 : (double)dxfFill.Gradient.Bottom; + var left = dxfFill.Gradient.Left == null ? 0 : (double)dxfFill.Gradient.Left; + var right = dxfFill.Gradient.Right == null ? 0 : (double)dxfFill.Gradient.Right; + fill.SetGradient(dictionaries, (EPPlus.Export.Pdf.Enums.ExcelFillGradientType)gradientType, color1, color2, color3, degree, top, bottom, left, right); + } + } + else + { + if (xfFill.PatternType == ExcelFillStyle.Solid) + { + var bkgc = xfFill.BackgroundColor; + var patternStyle = xfFill.PatternType; + if (string.IsNullOrEmpty(bkgc.LookupColor()) && !string.IsNullOrEmpty(text)) + { + fill.SetFill(Color.Empty); + } + else + { + fill.SetFill(PdfColor.SetColorFromHex(bkgc.LookupColor())); + } + } + else if (xfFill.PatternType != ExcelFillStyle.None) + { + var patternStyle = xfFill.PatternType; + var bkgc = PdfColor.SetColorFromHex(xfFill.PatternColor.Rgb == null ? "#FFFFFFFF" : xfFill.PatternColor.LookupColor()); + var patc = PdfColor.SetColorFromHex(xfFill.BackgroundColor.LookupColor()); + fill.SetPattern(dictionaries, (EPPlus.Export.Pdf.Enums.ExcelFillStyle)patternStyle, bkgc, patc); + } + else if (xfFill.HasGradient) + { + var gradientType = xfFill.Gradient.Type; + var color1 = PdfColor.SetColorFromHex(xfFill.Gradient.Color1.LookupColor()); + var color2 = PdfColor.SetColorFromHex(xfFill.Gradient.Color2.LookupColor()); + var color3 = PdfColor.SetColorFromHex(xfFill.Gradient.Color3.LookupColor()); + var degree = xfFill.Gradient.Degree; + var top = double.IsNaN(xfFill.Gradient.Top) ? 0 : xfFill.Gradient.Top; + var bottom = double.IsNaN(xfFill.Gradient.Bottom) ? 0 : xfFill.Gradient.Bottom; + var left = double.IsNaN(xfFill.Gradient.Left) ? 0 : xfFill.Gradient.Left; + var right = double.IsNaN(xfFill.Gradient.Right) ? 0 : xfFill.Gradient.Right; + fill.SetGradient(dictionaries, (EPPlus.Export.Pdf.Enums.ExcelFillGradientType)gradientType, color1, color2, color3, degree, top, bottom, left, right); + } + } + } + + static MergedCellCorners GetCorners(ExcelAddressBase addr, int row, int col) + { + if (addr == null) return MergedCellCorners.All; + MergedCellCorners result = MergedCellCorners.None; + + if (row == addr.Start.Row && col == addr.Start.Column) + result |= MergedCellCorners.TopLeft; + + if (row == addr.Start.Row && col == addr.End.Column) + result |= MergedCellCorners.TopRight; + + if (row == addr.End.Row && col == addr.Start.Column) + result |= MergedCellCorners.BottomLeft; + + if (row == addr.End.Row && col == addr.End.Column) + result |= MergedCellCorners.BottomRight; + return result; + } + + private static bool NeedsClipping(PdfCell map, Page page, int row, int col) + { + if (map.ContentAligmnet == null) return false; + // Fill alignment always clips; WrapText is already wrapped but clip for safety. + if (map.ContentAligmnet.HorizontalAlignment == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Fill || map.ContentAligmnet.WrapText) + return true; + if (map.TotalTextLength <= map.ColumnWidth) return false; + var halign = map.ContentAligmnet.HorizontalAlignment; + if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left || halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General) + { + // Text spills right — clip if the right neighbour has content or we're at the page edge. + if (col >= page.ToColumn) return true; + var right = page.Map[row, col + 1]; + return right != null && !string.IsNullOrEmpty(right.Text); + } + else if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) + { + // Text spills left — clip if the left neighbour has content or we're at the page edge. + if (col <= page.FromColumn) return true; + var left = page.Map[row, col - 1]; + return left != null && !string.IsNullOrEmpty(left.Text); + } + else if (halign == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) + { + // Text spills both ways — clip if either neighbour blocks or we're at an edge. + bool rightBlocked = col >= page.ToColumn || (page.Map[row, col + 1] != null && !string.IsNullOrEmpty(page.Map[row, col + 1].Text)); + bool leftBlocked = col <= page.FromColumn || (page.Map[row, col - 1] != null && !string.IsNullOrEmpty(page.Map[row, col - 1].Text)); + return rightBlocked || leftBlocked; + } + return false; + } + private static bool HasBorder(PdfCellStyle cellStyle) + { + if (cellStyle == null) return false; + bool hasBorders = + cellStyle.xfTop.Style != ExcelBorderStyle.None || + cellStyle.xfBottom.Style != ExcelBorderStyle.None || + cellStyle.xfLeft.Style != ExcelBorderStyle.None || + cellStyle.xfRight.Style != ExcelBorderStyle.None || + (cellStyle.dxfTop?.HasValue ?? false) || + (cellStyle.dxfBottom?.HasValue ?? false) || + (cellStyle.dxfLeft?.HasValue ?? false) || + (cellStyle.dxfRight?.HasValue ?? false) || + (cellStyle.Diagonal != null && cellStyle.Diagonal.Style != ExcelBorderStyle.None); + return hasBorders; + } + + private static bool HasDiagonalBorder(PdfCellStyle style) => style?.Diagonal != null && style.Diagonal.Style != ExcelBorderStyle.None; + + private static void AddHeadingCell(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfPageLayout pageLayout, PdfCellStyle headingStyle, string label, double x, double y, double width, double height, string fontName, float fontSize, string namePrefix) + { + if (width == 0d || height == 0d) return; + var fill = new PdfCellLayout(x, y, width, height); + SetFill(dictionaries, headingStyle, label, fill); + fill.Name = namePrefix; + fill.IsHeading = true; + fill.UpdateShadingPositionMatrix(pageSettings); + pageLayout.AddChild(fill); + var cell = CreateHeadingPdfCell(pageSettings, dictionaries, label, ExcelHorizontalAlignment.Center, width, height, fontName, fontSize); + if (cell.TextLines != null && cell.TextLines.Count > 0) + { + var info = new MergedCellDrawInfo { X = x, Y = y, Width = width, Height = height }; + var text = new PdfCellContentLayout(pageSettings, dictionaries, cell, info, x, y, width, height); + text.Name = namePrefix + "_Text"; + text.IsHeading = true; + text.GidsAndCharMap(dictionaries); + pageLayout.AddChild(text); + } + AddHeadingCellBorder(pageLayout, x, y, width, height); + } + + private static void AddHeadingCells(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Page page, PdfPageLayout pageLayout, double contentStartX, double contentStartY, double headingWidth, double headingHeight, string fontName, float fontSize, ExcelFill fill) + { + var headingStyle = new PdfCellStyle(); + headingStyle.xfFill = fill; + var cornerFill = new PdfCellLayout(pageSettings.ContentBounds.Left, pageSettings.ContentBounds.Top, headingWidth, headingHeight); + SetFill(dictionaries, headingStyle, "", cornerFill); + cornerFill.Name = "Heading_Corner"; + cornerFill.UpdateShadingPositionMatrix(pageSettings); + pageLayout.AddChild(cornerFill); + double x = contentStartX; + for (int col = page.FromColumn; col <= page.ToColumn; col++) + { + double colWidth = page.Map[page.FromRow, col]?.ColumnWidth ?? 0d; + if (colWidth == 0d) { x += colWidth; continue; } + string colLetter = ExcelCellBase.GetColumnLetter(col); + AddHeadingCell(pageSettings, dictionaries, pageLayout, headingStyle, colLetter, + x, pageSettings.ContentBounds.Top, colWidth, headingHeight, fontName, fontSize, "Heading_Col_" + colLetter); + x += colWidth; + } + double y = contentStartY; + for (int row = page.FromRow; row <= page.ToRow; row++) + { + double rowHeight = page.RowHeights[row - page.FromRow]; + if (rowHeight == 0d) { y -= rowHeight; continue; } + string rowNum = row.ToString(); + AddHeadingCell(pageSettings, dictionaries, pageLayout, headingStyle, rowNum, + pageSettings.ContentBounds.Left, y, headingWidth, rowHeight, fontName, fontSize, "Heading_Row_" + rowNum); + y -= rowHeight; + } + } + + private static void AddPrintTitleHeadings(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Page page, PdfPageLayout pageLayout, string fontName, float fontSize, ExcelFill fill) + { + if (page.PrintTitleHeadings == null || page.PrintTitleHeadings.Count == 0) return; + + var headingStyle = new PdfCellStyle(); + headingStyle.xfFill = fill; + + foreach (var h in page.PrintTitleHeadings) + { + string label = h.IsRow ? h.Index.ToString() : ExcelCellBase.GetColumnLetter(h.Index); + string namePrefix = (h.IsRow ? "Heading_Row_" : "Heading_Col_") + label; + AddHeadingCell(pageSettings, dictionaries, pageLayout, headingStyle, label, h.X, h.Y, h.Width, h.Height, fontName, fontSize, namePrefix); + } + } + + private static void AddHeadingCellBorder(PdfPageLayout pageLayout, double x, double y, double width, double height) + { + double right = x + width; + double bottom = y - height; + pageLayout.BorderLines.Add(new GridLine(x, y, right, y)); // top + pageLayout.BorderLines.Add(new GridLine(x, bottom, right, bottom)); // bottom + pageLayout.BorderLines.Add(new GridLine(x, y, x, bottom)); // left + pageLayout.BorderLines.Add(new GridLine(right, y, right, bottom)); // right + } + + private static PdfCell CreateHeadingPdfCell(PdfPageSettings pageSettings, PdfDictionaries dictionaries, string text, ExcelHorizontalAlignment hAlign, double width, double height, string fontName, float fontSize) + { + var cell = new PdfCell(); + cell.ColumnWidth = width; + cell.Width = width; + cell.Height = height; + cell.Text = text; + cell.CellStyle = new PdfCellStyle(); + cell.ContentAligmnet = new PdfCellAlignmentData(); + cell.ContentAligmnet.HorizontalAlignment = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)hAlign; + cell.ContentAligmnet.VerticalAlignment = (EPPlus.Export.Pdf.Enums.ExcelVerticalAlignment)ExcelVerticalAlignment.Bottom; + cell.ContentAligmnet.WrapText = false; + if (!string.IsNullOrEmpty(text)) + { + var tf = new TextFragment(); + tf.Font = new RichTextFormatSimple(); + tf.Font.Family = fontName; + tf.Font.SubFamily = FontSubFamily.Regular; + tf.Font.Size = fontSize; + tf.Text = text; + tf.RichTextOptions.Bold = false; + tf.RichTextOptions.Italic = false; + tf.RichTextOptions.UnderlineType = 12; // none + tf.RichTextOptions.StrikeType = 1; // none + cell.TextFragments = new List { tf }; + PdfTextShaper.ShapeText(pageSettings, dictionaries, cell); + } + return cell; + } + + private static void AddSpillCells(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Page page, PdfPageLayout pageLayout) + { + if (page.SpillCells == null) return; + foreach (var s in page.SpillCells) + { + var map = s.Cell; + if (map.TextLines == null || map.TextLines.Count == 0) continue; + if (s.ClipWidth <= 0d || s.ClipHeight <= 0d) continue; + + var text = new PdfCellContentLayout(pageSettings, dictionaries, map, new MergedCellDrawInfo(), s.X, s.Y, s.Width, s.Height); + text.Name = "Spill_" + map.Name; + text.IsPrintTitle = s.IsPrintTitle; // false → clipped content group; true → outside-clip (band) + text.GidsAndCharMap(dictionaries); + text.SetupClipping(s.ClipX, s.ClipY, s.ClipWidth, s.ClipHeight); + pageLayout.AddChild(text); + } + } + + private static void AddPrintTitleCells(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Page page, PdfPageLayout pageLayout) + { + if (page.PrintTitleCells == null) return; + pageLayout.PrintTitleGridLines = page.PrintTitleGridLines ?? new List(); + foreach (var t in page.PrintTitleCells) + { + var map = t.Cell; + var fill = new PdfCellLayout(t.X, t.Y, t.Width, t.Height); + SetFill(dictionaries, map.CellStyle, map.Text, fill); + fill.Name = map.Name; + fill.IsPrintTitle = true; + fill.UpdateShadingPositionMatrix(pageSettings); + pageLayout.AddChild(fill); + + if (map.TextLines != null && map.TextLines.Count > 0) + { + var info = new MergedCellDrawInfo { X = t.X, Y = t.Y, Width = t.Width, Height = t.Height }; + var text = new PdfCellContentLayout(pageSettings, dictionaries, map, info, t.X, t.Y, t.Width, t.Height); + text.Name = map.Name; + text.IsPrintTitle = true; + text.GidsAndCharMap(dictionaries); + text.SetupClipping(t.ClipX, t.ClipY, t.ClipWidth, t.ClipHeight); + pageLayout.AddChild(text); + } + if (!map.Merged && HasBorder(map.CellStyle)) // was: if (HasBorder(map.CellStyle)) + { + var border = new PdfCellBorderLayout(false, MergedCellCorners.All, new MergedCellDrawInfo(), t.X, t.Y, t.Width, t.Height); + SetBorderStyle(map.CellStyle, border); + border.IsPrintTitle = true; + border.Name = "PrintTitleBorder_" + map.Name; + pageLayout.AddChild(border); + } + // Per-cell borders for merged band cells — outside the margin clip like the rest of the band. + foreach (var b in page.PrintTitleBorders) + { + var sub = b.Cell; + if (!HasBorder(sub.CellStyle)) continue; + var border = new PdfCellBorderLayout(false, MergedCellCorners.All, new MergedCellDrawInfo(), b.X, b.Y, b.Width, b.Height); + SetBorderStyle(sub.CellStyle, border); + border.IsPrintTitle = true; + border.Name = "PrintTitleMergeBorder_" + sub.Name; + pageLayout.AddChild(border); + } + } + } + + private static void SetBorderStyle(PdfCellStyle style, PdfCellBorderLayout border) + { + var topStyle = style.xfTop.Style == ExcelBorderStyle.None ? ((style.dxfTop != null && style.dxfTop.HasValue) ? (ExcelBorderStyle)style.dxfTop.Style : ExcelBorderStyle.None) : style.xfTop.Style; + var topColor = style.dxfTop != null ? PdfColor.SetColorFromHex(style.dxfTop.Color.LookupColor(style.dxfTop)) : PdfColor.SetColorFromHex(style.xfTop.Color.LookupColor(style.xfTop)); + + var bottomStyle = style.xfBottom.Style == ExcelBorderStyle.None ? ((style.dxfBottom != null && style.dxfBottom.HasValue) ? (ExcelBorderStyle)style.dxfBottom.Style : ExcelBorderStyle.None) : style.xfBottom.Style; + var bottomColor = style.dxfBottom != null ? PdfColor.SetColorFromHex(style.dxfBottom.Color.LookupColor(style.dxfBottom)) : PdfColor.SetColorFromHex(style.xfBottom.Color.LookupColor(style.xfBottom)); + + var leftStyle = style.xfLeft.Style == ExcelBorderStyle.None ? ((style.dxfLeft != null && style.dxfLeft.HasValue) ? (ExcelBorderStyle)style.dxfLeft.Style : ExcelBorderStyle.None) : style.xfLeft.Style; + var leftColor = style.dxfLeft != null ? PdfColor.SetColorFromHex(style.dxfLeft.Color.LookupColor(style.dxfLeft)) : PdfColor.SetColorFromHex(style.xfLeft.Color.LookupColor(style.xfLeft)); + + var rightStyle = style.xfRight.Style == ExcelBorderStyle.None ? ((style.dxfRight != null && style.dxfRight.HasValue) ? (ExcelBorderStyle)style.dxfRight.Style : ExcelBorderStyle.None) : style.xfRight.Style; + var rightColor = style.dxfRight != null ? PdfColor.SetColorFromHex(style.dxfRight.Color.LookupColor(style.dxfRight)) : PdfColor.SetColorFromHex(style.xfRight.Color.LookupColor(style.xfRight)); + + var diagUpStyle = style.DiagonalUp ? style.Diagonal.Style : ExcelBorderStyle.None; + var diagUpColor = style.DiagonalUp ? PdfColor.SetColorFromHex(style.Diagonal.Color.LookupColor(style.Diagonal)) : Color.Transparent; + + var diagDownStyle = style.DiagonalDown ? style.Diagonal.Style : ExcelBorderStyle.None; + var diagDownColor = style.DiagonalDown ? PdfColor.SetColorFromHex(style.Diagonal.Color.LookupColor(style.Diagonal)) : Color.Transparent; + + border.SetStyle((EPPlus.Export.Pdf.Enums.ExcelBorderStyle)topStyle, topColor, + (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)bottomStyle, bottomColor, + (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)leftStyle, leftColor, + (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)rightStyle, rightColor, + (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)diagUpStyle, diagUpColor, + (EPPlus.Export.Pdf.Enums.ExcelBorderStyle)diagDownStyle, diagDownColor); + } + private static int GetTotalPages(List pdfPages) + { + int totalPages = 0; + for (int i = 0; i < pdfPages.Count; i++) + { + totalPages += pdfPages[i].Page.Length; + } + return totalPages; + } + + internal static List GetPages(PdfPageSettings pageSettings, PdfWorksheet[] pdfSheets) + { + List PagesCollection = new List(); + foreach (var pdfSheet in pdfSheets) + { + for (int ri = 0; ri < pdfSheet.Ranges.Count; ri++) + { + var range = pdfSheet.Ranges[ri]; + var pages = GetNumberOfPages(pageSettings, pdfSheet, ref range); + pages = AssignRangeToPages(pageSettings, range, pages); + pages = MapPage(range, pages); + pages = GetHeaderFooter(range, pages, pdfSheet); + pages = PrecomputeMergedCells(pageSettings, range, pages); + pages = PrecomputeSpillCells(pageSettings, range, pages); + pages = PrecomputePrintTitleCells(pageSettings, pdfSheet, range, pages); + pages.HeadingFontName = pdfSheet.NormalStyle.Style.Font.Name; + pages.HeadingFontSize = pdfSheet.NormalStyle.Style.Font.Size; + pages.HeadingFill = pdfSheet.NormalStyle.Style.Fill; + PagesCollection.Add(pages); + } + if (pdfSheet.CommentsAndNotes.Range != null) + { + bool savedShowHeadings = pageSettings.ShowHeadings; + pageSettings.ShowHeadings = false; + var pages = GetNumberOfPages(pageSettings, pdfSheet, ref pdfSheet.CommentsAndNotes); + pages = AssignRangeToPages(pageSettings, pdfSheet.CommentsAndNotes, pages); + pages = MapPage(pdfSheet.CommentsAndNotes, pages); + pageSettings.ShowHeadings = savedShowHeadings; + pages.IsCommentsPage = true; + PagesCollection.Add(pages); + } + } + return PagesCollection; + } + + internal static Pages PrecomputeMergedCells(PdfPageSettings pageSettings, PdfRange range, Pages pdfPages) + { + for (int i = 0; i < pdfPages.Page.Length; i++) + pdfPages.Page[i] = PrecomputePageMergedCells(pageSettings, range, pdfPages.Page[i]); + return pdfPages; + } + + private static Page PrecomputePageMergedCells(PdfPageSettings pageSettings, PdfRange range, Page page) + { + page.MergedCells = new Dictionary(); + // Build a quick lookup: absolute x for each column index on this page. + // We read ColumnWidth from the first data row; widths are per-column, not per-cell. + var colX = BuildColumnXPositions(pageSettings, page); + for (int row = page.FromRow; row <= page.ToRow; row++) + { + for (int col = page.FromColumn; col <= page.ToColumn; col++) + { + var cell = page.Map[row, col]; + if (cell == null || !cell.Merged) continue; + string key = cell.MergedAddress.Address; + if (page.MergedCells.ContainsKey(key)) continue; + var addr = cell.MergedAddress; + var mainCell = cell.Main ?? cell; // Main == null means this cell IS the top-left + // --- X --- + // Start from the current column and walk left to the merge origin. + // Columns within the current page come from colX; columns that lie on + // a preceding column-page come from range.ColWidths. + double drawX = colX[col - page.FromColumn]; + for (int c = addr._fromCol; c < col; c++) + { + int rangeIdx = c - range.Range._fromCol; + if (rangeIdx >= 0 && rangeIdx < range.ColWidths.Count) + drawX -= range.ColWidths[rangeIdx]; + } + // --- Y --- + // Replace the * 15d line with a sum of real row heights + double drawY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight; + for (int r = page.FromRow; r < row; r++) + { + drawY -= range.RowHeights[r - range.Range._fromRow].Height; + } + // Existing loop — just add .Height + for (int r = addr._fromRow; r < row; r++) + { + int rangeIdx = r - range.Range._fromRow; + if (rangeIdx >= 0 && rangeIdx < range.RowHeights.Count) + drawY += range.RowHeights[rangeIdx].Height; + } + page.MergedCells[key] = new MergedCellDrawInfo + { + X = drawX, + Y = drawY, + Width = mainCell.Width, + Height = mainCell.Height + }; + } + } + return page; + } + + private static double[] BuildColumnXPositions(PdfPageSettings pageSettings, Page page) + { + int colCount = page.ToColumn - page.FromColumn + 1; + var colX = new double[colCount]; + double x = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth; + for (int col = page.FromColumn; col <= page.ToColumn; col++) + { + colX[col - page.FromColumn] = x; + var cell = page.Map[page.FromRow, col]; + x += cell?.ColumnWidth ?? 0d; + } + return colX; + } + + private static void ComputePrintTitleDimensions(PdfWorksheet pdfSheet, PdfRange range, out double titleHeight, out double titleWidth) + { + titleHeight = 0d; + titleWidth = 0d; + if (pdfSheet.PrintTitleRowFrom >= 0) + { + for (int r = pdfSheet.PrintTitleRowFrom; r <= pdfSheet.PrintTitleRowTo; r++) + { + int idx = r - range.Range._fromRow; + if (idx >= 0 && idx < range.RowHeights.Count) + titleHeight += range.RowHeights[idx].Height; + } + } + if (pdfSheet.PrintTitleColFrom >= 0) + { + for (int c = pdfSheet.PrintTitleColFrom; c <= pdfSheet.PrintTitleColTo; c++) + { + int idx = c - range.Range._fromCol; + if (idx >= 0 && idx < range.ColWidths.Count) + titleWidth += range.ColWidths[idx]; + } + } + } + + internal static Pages PrecomputePrintTitleCells(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, PdfRange range, Pages pdfPages) + { + for (int i = 0; i < pdfPages.Page.Length; i++) + pdfPages.Page[i] = PrecomputePagePrintTitleCells(pageSettings, pdfSheet, range, pdfPages.Page[i]); + return pdfPages; + } + + private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, PdfRange range, Page page) + { + page.PrintTitleCells = new List(); + page.PrintTitleBorders = new List(); + + bool topBand = page.PrintTitleHeight > 0d && pdfSheet.PrintTitleRowFrom >= 0 && page.FromRow > pdfSheet.PrintTitleRowTo; + bool leftBand = page.PrintTitleWidth > 0d && pdfSheet.PrintTitleColFrom >= 0 && page.FromColumn > pdfSheet.PrintTitleColTo; + if (!topBand && !leftBand) return page; + + // Content-column X: same origin/widths the content loop uses (step-2 origin). + var contentColX = new Dictionary(); + double cx = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth; + for (int c = page.FromColumn; c <= page.ToColumn; c++) + { + contentColX[c] = cx; + cx += RangeColWidth(range, page.FromRow, c); + } + // Content-row Y. + var contentRowY = new Dictionary(); + double cy = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight; + for (int r = page.FromRow; r <= page.ToRow; r++) + { + contentRowY[r] = cy; + cy -= RangeRowHeight(range, r); + } + // Title-column X (left band): just right of the heading gutter. + var titleColX = new Dictionary(); + if (leftBand) + { + double tx = pageSettings.ContentBounds.Left + page.HeadingWidth; + for (int c = pdfSheet.PrintTitleColFrom; c <= pdfSheet.PrintTitleColTo; c++) + { + titleColX[c] = tx; + tx += RangeColWidth(range, page.FromRow, c); + } + } + // Title-row Y (top band): just below the heading gutter. + var titleRowY = new Dictionary(); + if (topBand) + { + double ty = pageSettings.ContentBounds.Top - page.HeadingHeight; + for (int r = pdfSheet.PrintTitleRowFrom; r <= pdfSheet.PrintTitleRowTo; r++) + { + titleRowY[r] = ty; + ty -= RangeRowHeight(range, r); + } + } + if (topBand) + ProcessBandRegionCells(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, page.FromColumn, page.ToColumn, contentColX, titleRowY); + if (leftBand) + ProcessBandRegionCells(page, range, page.FromRow, page.ToRow, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, titleColX, contentRowY); + if (topBand && leftBand) + ProcessBandRegionCells(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, titleColX, titleRowY); + + page.PrintTitleGridLines = new List(); + if (pageSettings.ShowGridLines) + { + if (topBand) + EmitBandGrid(page.PrintTitleGridLines, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, page.FromColumn, page.ToColumn, + BandEdgesX(contentColX, page.FromColumn, page.ToColumn, range, page.FromRow), + BandEdgesY(titleRowY, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, range)); + if (leftBand) + EmitBandGrid(page.PrintTitleGridLines, range, page.FromRow, page.ToRow, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, + BandEdgesX(titleColX, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, range, page.FromRow), + BandEdgesY(contentRowY, page.FromRow, page.ToRow, range)); + if (topBand && leftBand) + EmitBandGrid(page.PrintTitleGridLines, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, + BandEdgesX(titleColX, pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, range, page.FromRow), + BandEdgesY(titleRowY, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, range)); + } + // ---- band headings: original row numbers / column letters, in the gutter gaps ---- + page.PrintTitleHeadings = new List(); + if (pageSettings.ShowHeadings) + { + if (topBand) + for (int r = pdfSheet.PrintTitleRowFrom; r <= pdfSheet.PrintTitleRowTo; r++) + { + double h = RangeRowHeight(range, r); + if (h <= 0d) continue; + page.PrintTitleHeadings.Add(new PrintTitleHeadingDraw + { + IsRow = true, + Index = r, + X = pageSettings.ContentBounds.Left, + Y = titleRowY[r], + Width = page.HeadingWidth, + Height = h + }); + } + + if (leftBand) + for (int c = pdfSheet.PrintTitleColFrom; c <= pdfSheet.PrintTitleColTo; c++) + { + double w = RangeColWidth(range, page.FromRow, c); + if (w <= 0d) continue; + page.PrintTitleHeadings.Add(new PrintTitleHeadingDraw + { + IsRow = false, + Index = c, + X = titleColX[c], + Y = pageSettings.ContentBounds.Top, + Width = w, + Height = page.HeadingHeight + }); + } + } + + // repeated title-row text continues onto the next horizontal page's band + if (topBand) + AddIncomingSpill(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, page.FromColumn, page.ToColumn, + pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth, + pageSettings.ContentBounds.Top - page.HeadingHeight, + isPrintTitle: true); + + // left band: a neighbour whose text spills INTO a title column travels with the repeated column + if (leftBand) + AddIncomingSpill(page, range, page.FromRow, page.ToRow, + pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, + pageSettings.ContentBounds.Left + page.HeadingWidth, // band origin X (left edge of the title columns) + pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight, // content-rows origin Y + isPrintTitle: true); + + // corner: same, for the title-rows × title-columns intersection + if (topBand && leftBand) + AddIncomingSpill(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, + pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo, + pageSettings.ContentBounds.Left + page.HeadingWidth, // band origin X + pageSettings.ContentBounds.Top - page.HeadingHeight, // title-rows origin Y + isPrintTitle: true); + + return page; + } + + private static void ProcessBandRegionCells(Page page, PdfRange range, int fromRow, int toRow, int fromCol, int toCol, Dictionary colX, Dictionary rowY) + { + // Band-region rectangle (top-left origin). Non-merged text may spill within this rect, + // which is bounded by the band edge, so it can never overflow into the content area. + double regLeft = colX[fromCol]; + double regRight = colX[toCol] + RangeColWidth(range, page.FromRow, toCol); + double regTop = rowY[fromRow]; + double regBottom = rowY[toRow] - RangeRowHeight(range, toRow); + double regW = regRight - regLeft; + double regH = regTop - regBottom; + var drawnMerges = new HashSet(); + for (int r = fromRow; r <= toRow; r++) + { + for (int c = fromCol; c <= toCol; c++) + { + var cell = RangeCell(range, r, c); + if (cell == null) continue; + + if (cell.Merged) + { + if (!drawnMerges.Add(cell.MergedAddress.Address)) continue; + var addr = cell.MergedAddress; + var main = cell.Main ?? cell; + int vFromCol = Math.Max(addr._fromCol, fromCol); + int vToCol = Math.Min(addr._toCol, toCol); + int vFromRow = Math.Max(addr._fromRow, fromRow); + int vToRow = Math.Min(addr._toRow, toRow); + if (vFromCol > vToCol || vFromRow > vToRow) continue; + double x = colX[vFromCol]; + double width = (colX[vToCol] + RangeColWidth(range, page.FromRow, vToCol)) - colX[vFromCol]; + double y = rowY[vFromRow]; + double height = (rowY[vFromRow] - rowY[vToRow]) + RangeRowHeight(range, vToRow); + if (width <= 0d || height <= 0d) continue; + // merged cells don't spill — clip text to the merge itself (matches content) + page.PrintTitleCells.Add(new PrintTitleCellDraw + { + Cell = main, + X = x, + Y = y, + Width = width, + Height = height, + ClipX = x, + ClipY = y, + ClipWidth = width, + ClipHeight = height + }); + for (int br = vFromRow; br <= vToRow; br++) + { + double bh = RangeRowHeight(range, br); + if (bh <= 0d) continue; + for (int bc = vFromCol; bc <= vToCol; bc++) + { + double bw = RangeColWidth(range, page.FromRow, bc); + if (bw <= 0d) continue; + var sub = RangeCell(range, br, bc); + if (sub == null || !HasBorder(sub.CellStyle)) continue; + page.PrintTitleBorders.Add(new PrintTitleCellDraw + { + Cell = sub, + X = colX[bc], + Y = rowY[br], + Width = bw, + Height = bh + }); + } + } + } + else + { + double w = RangeColWidth(range, page.FromRow, c); + double h = RangeRowHeight(range, r); + if (w <= 0d || h <= 0d) continue; + // non-merged: clip to the band region so text can spill within it but not into content + page.PrintTitleCells.Add(new PrintTitleCellDraw + { + Cell = cell, + X = colX[c], + Y = rowY[r], + Width = w, + Height = h, + ClipX = regLeft, + ClipY = regTop, + ClipWidth = regW, + ClipHeight = regH + }); + } + } + } + } + + private static void EmitBandGrid(List target, PdfRange range, int fromRow, int toRow, int fromCol, int toCol, double[] colX, double[] rowY) + { + int nr = toRow - fromRow + 1; + int nc = toCol - fromCol + 1; + if (nr <= 0 || nc <= 0) return; + var spill = BuildBandSpillMask(range, fromRow, toRow, fromCol, toCol, colX); + double top = rowY[0], bottom = rowY[nr]; + double left = colX[0], right = colX[nc]; + EmitBandFrameH(target, range, top, fromRow, fromCol, nc, colX, CellHasTopBorder); + EmitBandFrameH(target, range, bottom, toRow, fromCol, nc, colX, CellHasBottomBorder); + EmitBandFrameV(target, range, left, fromCol, fromRow, nr, rowY, CellHasLeftBorder); + EmitBandFrameV(target, range, right, toCol, fromRow, nr, rowY, CellHasRightBorder); + // interior verticals — suppress where a merge spans the gap + for (int gi = 1; gi < nc; gi++) + { + int leftCol = fromCol + gi - 1, rightCol = leftCol + 1; + double x = colX[gi]; + double? runStart = null; double runEnd = 0d; + for (int ri = 0; ri < nr; ri++) + { + int r = fromRow + ri; + //bool block = SameMerge(range, r, leftCol, r, rightCol) || spill[ri, gi]; + bool block = SameMerge(range, r, leftCol, r, rightCol) || spill[ri, gi] || + CellHasRightBorder(RangeCell(range, r, leftCol)) || + CellHasLeftBorder(RangeCell(range, r, rightCol)); + if (!block) { if (runStart == null) runStart = rowY[ri]; runEnd = rowY[ri + 1]; } + else if (runStart != null) { target.Add(new GridLine(x, runStart.Value, x, runEnd)); runStart = null; } + } + if (runStart != null) target.Add(new GridLine(x, runStart.Value, x, runEnd)); + } + // interior horizontals — suppress where a merge spans the gap + for (int gj = 1; gj < nr; gj++) + { + int topRow = fromRow + gj - 1, bottomRow = topRow + 1; + double y = rowY[gj]; + double? runStart = null; double runEnd = 0d; + for (int ci = 0; ci < nc; ci++) + { + int c = fromCol + ci; + bool block = SameMerge(range, topRow, c, bottomRow, c) || + CellHasBottomBorder(RangeCell(range, topRow, c)) || + CellHasTopBorder(RangeCell(range, bottomRow, c)); + if (!block) { if (runStart == null) runStart = colX[ci]; runEnd = colX[ci + 1]; } + else if (runStart != null) { target.Add(new GridLine(runStart.Value, y, runEnd, y)); runStart = null; } + } + if (runStart != null) target.Add(new GridLine(runStart.Value, y, runEnd, y)); + } + } + + private static bool[,] BuildBandSpillMask(PdfRange range, int fromRow, int toRow, int fromCol, int toCol, double[] colX) + { + int nr = toRow - fromRow + 1; + int nc = toCol - fromCol + 1; + var blocked = new bool[Math.Max(nr, 1), Math.Max(nc, 1)]; // [ri, g], g in 1..nc-1 + if (nr <= 0 || nc <= 1) return blocked; + int repRow = fromRow; + for (int ri = 0; ri < nr; ri++) + { + int row = fromRow + ri; + // (a) cells spilling within the band region + for (int ci = 0; ci < nc; ci++) + { + var cell = RangeCell(range, row, fromCol + ci); + if (cell == null || cell.Merged) continue; + if (cell.ContentAligmnet != null && cell.ContentAligmnet.WrapText) continue; + if (string.IsNullOrEmpty(cell.Text)) continue; + double spill = cell.TotalTextLength - cell.ColumnWidth; + if (spill <= 0d) continue; + var hal = cell.ContentAligmnet?.HorizontalAlignment ?? (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + if (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left || hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General) + BandMarkRight(range, row, ci, nc, fromCol, colX, spill, ri, blocked); + else if (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) + BandMarkLeft(range, row, ci, fromCol, colX, spill, ri, blocked); + else if (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) + { + double half = spill / 2d; + BandMarkRight(range, row, ci, nc, fromCol, colX, half, ri, blocked); + BandMarkLeft(range, row, ci, fromCol, colX, half, ri, blocked); + } + } + // (b) spill entering from the LEFT of the region (left/general/center → spilling right in) + double lx = colX[0]; + for (int c = fromCol - 1; c >= range.Range._fromCol; c--) + { + double w = RangeColWidth(range, repRow, c); + lx -= w; + var cell = RangeCell(range, row, c); + if (cell == null) continue; + if (cell.Merged) break; + if (string.IsNullOrEmpty(cell.Text)) continue; + var hal = cell.ContentAligmnet?.HorizontalAlignment ?? (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + if (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) break; // spills away from the region + double rightExtent = (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) + ? lx + w / 2d + cell.TotalTextLength / 2d + : lx + cell.TotalTextLength; + for (int g = 1; g <= nc - 1; g++) + { + var blk = RangeCell(range, row, fromCol + g - 1); + if (blk != null && !string.IsNullOrEmpty(blk.Text)) break; + if (colX[g] < rightExtent) blocked[ri, g] = true; else break; + } + break; + } + + // (c) spill entering from the RIGHT of the region (right/center → spilling left in) + double rx = colX[nc]; + for (int c = toCol + 1; c <= range.Range._toCol; c++) + { + double w = RangeColWidth(range, repRow, c); + var cell = RangeCell(range, row, c); + if (cell == null) { rx += w; continue; } + if (cell.Merged) break; + if (string.IsNullOrEmpty(cell.Text)) { rx += w; continue; } + var hal = cell.ContentAligmnet?.HorizontalAlignment ?? (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + if (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left || hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General) break; // spills away + double leftExtent = (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) + ? rx + w / 2d - cell.TotalTextLength / 2d + : rx + w - cell.TotalTextLength; + for (int g = nc - 1; g >= 1; g--) + { + var blk = RangeCell(range, row, fromCol + g); + if (blk != null && !string.IsNullOrEmpty(blk.Text)) break; + if (colX[g] > leftExtent) blocked[ri, g] = true; else break; + } + break; + } + } + return blocked; + } + + private static void BandMarkRight(PdfRange range, int row, int ci, int nc, int fromCol, double[] colX, double spill, int ri, bool[,] blocked) + { + for (int g = ci + 1; g <= nc - 1; g++) + { + var rightCell = RangeCell(range, row, fromCol + g); + if (rightCell != null && !string.IsNullOrEmpty(rightCell.Text)) break; + double distToGap = colX[g] - colX[ci + 1]; + if (spill > distToGap) blocked[ri, g] = true; else break; + } + } + + private static void BandMarkLeft(PdfRange range, int row, int ci, int fromCol, double[] colX, double spill, int ri, bool[,] blocked) + { + for (int g = ci; g >= 1; g--) + { + var leftCell = RangeCell(range, row, fromCol + g - 1); + if (leftCell != null && !string.IsNullOrEmpty(leftCell.Text)) break; + double distToGap = colX[ci] - colX[g]; + if (spill > distToGap) blocked[ri, g] = true; else break; + } + } + + private static bool SameMerge(PdfRange range, int r1, int c1, int r2, int c2) + { + var a = RangeCell(range, r1, c1); + var b = RangeCell(range, r2, c2); + if (a == null || b == null || !a.Merged || !b.Merged) return false; + return a.MergedAddress.Address == b.MergedAddress.Address; + } + + // Column edges for a band region: left edge of every column fromCol..toCol, plus the trailing right edge. + private static double[] BandEdgesX(Dictionary leftX, int fromCol, int toCol, PdfRange range, int repRow) + { + int n = toCol - fromCol + 1; + var arr = new double[n + 1]; + for (int c = fromCol, k = 0; c <= toCol; c++, k++) arr[k] = leftX[c]; + arr[n] = leftX[toCol] + RangeColWidth(range, repRow, toCol); + return arr; + } + + // Row edges for a band region: top edge of every row fromRow..toRow, plus the trailing bottom edge. + private static double[] BandEdgesY(Dictionary topY, int fromRow, int toRow, PdfRange range) + { + int n = toRow - fromRow + 1; + var arr = new double[n + 1]; + for (int r = fromRow, k = 0; r <= toRow; r++, k++) arr[k] = topY[r]; + arr[n] = topY[toRow] - RangeRowHeight(range, toRow); + return arr; + } + + private static PdfCell RangeCell(PdfRange range, int row, int col) + { + if (row < range.Range._fromRow || row > range.Range._toRow) return null; + if (col < range.Range._fromCol || col > range.Range._toCol) return null; + return range.Map[row, col]; + } + + private static double RangeColWidth(PdfRange range, int representativeRow, int col) + { + var cell = RangeCell(range, representativeRow, col); + return cell?.ColumnWidth ?? 0d; + } + + private static double RangeRowHeight(PdfRange range, int row) + { + int i = row - range.Range._fromRow; + return (i >= 0 && i < range.RowHeights.Count) ? range.RowHeights[i].Height : 0d; + } + + internal static Pages GetNumberOfPages(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, ref PdfRange range) + { + var xPages = (int)Math.Max(1, Math.Ceiling(range.TotalWidth / pageSettings.ContentBounds.Width)); + var yPages = (int)Math.Max(1, Math.Ceiling(range.TotalHeight / pageSettings.ContentBounds.Height)); + + if (pageSettings.ShowHeadings) + { + int prev = 0; + do + { + prev = xPages; + range.AdditionalWidth = xPages * ((rowHeadingWith1CharWidth - pdfSheet.ZeroCharWidth) + (Math.Abs(pdfSheet.ToRow).ToString().Length * pdfSheet.ZeroCharWidth)); + xPages = (int)Math.Max(1, Math.Ceiling((range.TotalWidth + range.AdditionalWidth) / pageSettings.ContentBounds.Width)); + } while (prev != xPages); + do + { + prev = yPages; + range.AdditionalHeight = yPages * pdfSheet.Worksheet.DefaultRowHeight; + yPages = (int)Math.Max(1, Math.Ceiling((range.TotalHeight + range.AdditionalHeight) / pageSettings.ContentBounds.Height)); + } while (prev != yPages); + } + for (int i = range.Range._fromCol; i <= range.Range._toCol; i++) + { + if (pdfSheet.Worksheet.Column(i).PageBreak) + xPages++; + } + for (int i = range.Range._fromRow; i <= range.Range._toRow; i++) + { + if (pdfSheet.Worksheet.Row(i).PageBreak) + yPages++; + } + ComputePrintTitleDimensions(pdfSheet, range, out range.PrintTitleHeight, out range.PrintTitleWidth); + range.PrintTitleRowTo = pdfSheet.PrintTitleRowFrom >= 0 ? pdfSheet.PrintTitleRowTo : -1; + range.PrintTitleColTo = pdfSheet.PrintTitleColFrom >= 0 ? pdfSheet.PrintTitleColTo : -1; + Pages p = new Pages(); + p.Width = xPages; + p.Height = yPages; + p.Page = null; + return p; + } + + internal static Pages AssignRangeToPages(PdfPageSettings pageSettings, PdfRange range, Pages pdfPages) + { + var pages = pdfPages; + var worksheet = range.Range.Worksheet; + var addedWidth = pages.Width > 0 ? range.AdditionalWidth / pages.Width : 0d; + var addedHeight = pages.Height > 0 ? range.AdditionalHeight / pages.Height : 0d; + + var colSegments = GetColumnSegments(pageSettings, range, worksheet, addedWidth, range.PrintTitleWidth, range.PrintTitleColTo); + var rowSegments = GetRowSegments(pageSettings, range, worksheet, addedHeight, range.PrintTitleHeight, range.PrintTitleRowTo); + + pages.Page = new Page[colSegments.Count * rowSegments.Count]; + int i = 0; + + if (pageSettings.PageOrders == PageOrders.DownThenOver) + { + for (int ci = 0; ci < colSegments.Count; ci++) + for (int ri = 0; ri < rowSegments.Count; ri++) + pages.Page[i++] = new Page + { + FromColumn = colSegments[ci].From, + ToColumn = colSegments[ci].To, + FromRow = rowSegments[ri].From, + ToRow = rowSegments[ri].To, + HeadingWidth = addedWidth, + HeadingHeight = addedHeight, + PrintTitleWidth = (range.PrintTitleColTo >= 0 && colSegments[ci].From > range.PrintTitleColTo) ? range.PrintTitleWidth : 0d, + PrintTitleHeight = (range.PrintTitleRowTo >= 0 && rowSegments[ri].From > range.PrintTitleRowTo) ? range.PrintTitleHeight : 0d, + }; + } + else //if (pageSettings.PageOrders == PageOrders.OverThenDown) + { + for (int ri = 0; ri < rowSegments.Count; ri++) + for (int ci = 0; ci < colSegments.Count; ci++) + pages.Page[i++] = new Page + { + FromColumn = colSegments[ci].From, + ToColumn = colSegments[ci].To, + FromRow = rowSegments[ri].From, + ToRow = rowSegments[ri].To, + HeadingWidth = addedWidth, + HeadingHeight = addedHeight, + PrintTitleWidth = (range.PrintTitleColTo >= 0 && colSegments[ci].From > range.PrintTitleColTo) ? range.PrintTitleWidth : 0d, + PrintTitleHeight = (range.PrintTitleRowTo >= 0 && rowSegments[ri].From > range.PrintTitleRowTo) ? range.PrintTitleHeight : 0d, + }; + } + pdfPages = pages; + return pdfPages; + } + + private struct PageSegment + { + public int From; + public int To; + public PageSegment(int from, int to) { From = from; To = to; } + } + + private static List GetColumnSegments(PdfPageSettings pageSettings, PdfRange range, ExcelWorksheet worksheet, double addedWidth, double titleWidth, int printTitleColTo) + { + var segments = new List(); + int segStartIdx = 0; + double width = 0d; + for (int col = 0; col < range.ColWidths.Count; col++) + { + int actualCol = range.Range._fromCol + col; + bool reserveTitle = titleWidth > 0d && printTitleColTo >= 0 && (range.Map.FromColumn + segStartIdx) > printTitleColTo; + double effectiveAdded = addedWidth + (reserveTitle ? titleWidth : 0d); + // Content-bounds overflow: col doesn't fit, end segment before it and reprocess. + if (width + range.ColWidths[col] + effectiveAdded >= pageSettings.ContentBounds.Width) + { + segments.Add(new PageSegment(range.Map.FromColumn + segStartIdx, range.Map.FromColumn + col - 1)); + segStartIdx = col; + width = 0d; + col--; // reprocess this col as the first col of the next segment + continue; + } + width += range.ColWidths[col]; + // Explicit page break: col is included on this page, next segment starts after it. + if (worksheet.Column(actualCol).PageBreak) + { + segments.Add(new PageSegment(range.Map.FromColumn + segStartIdx, range.Map.FromColumn + col)); + segStartIdx = col + 1; + width = 0d; + } + } + // Remaining cols form the last segment. + if (segStartIdx < range.ColWidths.Count) + segments.Add(new PageSegment(range.Map.FromColumn + segStartIdx, range.Map.FromColumn + range.ColWidths.Count - 1)); + return segments; + } + + private static List GetRowSegments(PdfPageSettings pageSettings, PdfRange range, ExcelWorksheet worksheet, double addedHeight, double titleHeight, int printTitleRowTo) + { + var segments = new List(); + int segStartIdx = 0; + double height = 0d; + for (int row = 0; row < range.RowHeights.Count; row++) + { + int actualRow = range.Range._fromRow + row; + bool reserveTitle = titleHeight > 0d && printTitleRowTo >= 0 && (range.Map.FromRow + segStartIdx) > printTitleRowTo; + double effectiveAdded = addedHeight + (reserveTitle ? titleHeight : 0d); + // Content-bounds overflow: row doesn't fit, end segment before it and reprocess. + if (height + range.RowHeights[row].Height + effectiveAdded >= pageSettings.ContentBounds.Height) + { + segments.Add(new PageSegment(range.Map.FromRow + segStartIdx, range.Map.FromRow + row - 1)); + segStartIdx = row; + height = 0d; + row--; // reprocess this row as the first row of the next segment + continue; + } + height += range.RowHeights[row].Height; + // Explicit page break: row is included on this page, next segment starts after it. + if (worksheet.Row(actualRow).PageBreak) + { + segments.Add(new PageSegment(range.Map.FromRow + segStartIdx, range.Map.FromRow + row)); + segStartIdx = row + 1; + height = 0d; + } + } + // Remaining rows form the last segment. + if (segStartIdx < range.RowHeights.Count) + segments.Add(new PageSegment(range.Map.FromRow + segStartIdx, range.Map.FromRow + range.RowHeights.Count - 1)); + return segments; + } + + internal static Pages MapPage(PdfRange range, Pages pdfPages) + { + var pages = pdfPages; + for (int i = 0; i < pdfPages.Page.Length; i++) + { + var page = pdfPages.Page[i]; + page.Map = new PdfCellCollection(page.FromRow, page.ToRow, page.FromColumn, page.ToColumn); + page.RowHeights = new double[page.ToRow - page.FromRow + 1]; + for (int row = page.FromRow; row <= page.ToRow; row++) + { + int rangeIdx = row - range.Range._fromRow; + page.RowHeights[row - page.FromRow] = range.RowHeights[rangeIdx].Height; + for (int col = page.FromColumn; col <= page.ToColumn; col++) + { + page.Map[row, col] = range.Map[row, col]; + } + } + pdfPages.Page[i] = page; + } + pdfPages = pages; + return pdfPages; + } + + private static Pages GetHeaderFooter(PdfRange range, Pages pdfPages, PdfWorksheet pdfSheet) + { + var pages = pdfPages; + for (int i = 0; i < pdfPages.Page.Length; i++) + { + var page = pdfPages.Page[i]; + page.HeaderFooters = pdfSheet.HeaderFooters; + pdfPages.Page[i] = page; + } + pdfPages = pages; + return pdfPages; + } + + private static void SubstitutePageNumbers(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfHeaderFooter hf, int pageNumber, int totalPages) + { + if (hf == null) return; + if (hf.PageNumberIndexes.Count > 0) + { + foreach (var idx in hf.PageNumberIndexes) + hf.Content.TextFragments[idx].Text = pageNumber.ToString(); + } + if (hf.NumberOfPagesIndexes.Count > 0) + { + foreach (var idx in hf.NumberOfPagesIndexes) + hf.Content.TextFragments[idx].Text = totalPages.ToString(); + } + PdfTextShaper.ShapeText(pageSettings, dictionaries, hf.Content); + } + + private static void AddIncomingSpill(Page page, PdfRange range, int fromRow, int toRow, int windowFromCol, int windowToCol, double windowOriginX, double windowOriginY, bool isPrintTitle) + { + if (page.SpillCells == null) return; // initialised by the caller + double windowRightX = windowOriginX; + for (int c = windowFromCol; c <= windowToCol; c++) windowRightX += RangeColWidth(range, page.FromRow, c); + double rowTop = windowOriginY; + for (int r = fromRow; r <= toRow; r++) + { + double rowH = RangeRowHeight(range, r); + double y = rowTop; + rowTop -= rowH; + if (rowH <= 0d) continue; + // spill entering from the LEFT (left/general/center) + double lx = windowOriginX; + for (int c = windowFromCol - 1; c >= range.Range._fromCol; c--) + { + double w = RangeColWidth(range, page.FromRow, c); + lx -= w; + var cell = RangeCell(range, r, c); + if (cell == null) continue; + if (cell.Merged) break; // merges don't spill, and block + if (string.IsNullOrEmpty(cell.Text)) continue; + var hal = cell.ContentAligmnet?.HorizontalAlignment ?? (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + double rightExtent = + (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) ? lx + w / 2d + cell.TotalTextLength / 2d : + (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) ? lx + w : lx + cell.TotalTextLength; + if (rightExtent > windowOriginX) + { + double clipRight = FirstBlockedX(page, range, r, windowFromCol, windowToCol, windowOriginX, windowRightX, fromLeft: true); + page.SpillCells.Add(new SpillCellDraw + { + Cell = cell, + X = lx, + Y = y, + Width = w, + Height = rowH, + ClipX = windowOriginX, + ClipY = y, + ClipWidth = clipRight - windowOriginX, + ClipHeight = rowH, + IsPrintTitle = isPrintTitle + }); + } + break; + } + // spill entering from the RIGHT (right/center) + double rx = windowRightX; + for (int c = windowToCol + 1; c <= range.Range._toCol; c++) + { + double w = RangeColWidth(range, page.FromRow, c); + var cell = RangeCell(range, r, c); + if (cell == null) { rx += w; continue; } + if (cell.Merged) break; + if (string.IsNullOrEmpty(cell.Text)) { rx += w; continue; } + var hal = cell.ContentAligmnet?.HorizontalAlignment ?? (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + double leftExtent = + (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center) ? rx + w / 2d - cell.TotalTextLength / 2d : + (hal == (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right) ? rx + w - cell.TotalTextLength : rx; + if (leftExtent < windowRightX) + { + double clipLeft = FirstBlockedX(page, range, r, windowFromCol, windowToCol, windowOriginX, windowRightX, fromLeft: false); + page.SpillCells.Add(new SpillCellDraw + { + Cell = cell, + X = rx, + Y = y, + Width = w, + Height = rowH, + ClipX = clipLeft, + ClipY = y, + ClipWidth = windowRightX - clipLeft, + ClipHeight = rowH, + IsPrintTitle = isPrintTitle + }); + } + break; + } + } + } + + // Where spill into the window is cut off by the first non-empty (or merged) cell inside it. + private static double FirstBlockedX(Page page, PdfRange range, int row, int windowFromCol, int windowToCol, double windowOriginX, double windowRightX, bool fromLeft) + { + if (fromLeft) + { + double x = windowOriginX; + for (int c = windowFromCol; c <= windowToCol; c++) + { + var cell = RangeCell(range, row, c); + if (cell != null && (cell.Merged || !string.IsNullOrEmpty(cell.Text))) return x; + x += RangeColWidth(range, page.FromRow, c); + } + return windowRightX; + } + double rx = windowRightX; + for (int c = windowToCol; c >= windowFromCol; c--) + { + double w = RangeColWidth(range, page.FromRow, c); + rx -= w; + var cell = RangeCell(range, row, c); + if (cell != null && (cell.Merged || !string.IsNullOrEmpty(cell.Text))) return rx + w; + } + return windowOriginX; + } + + internal static Pages PrecomputeSpillCells(PdfPageSettings pageSettings, PdfRange range, Pages pdfPages) + { + for (int i = 0; i < pdfPages.Page.Length; i++) + { + var page = pdfPages.Page[i]; + page.SpillCells = new List(); + double originX = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth; + double originY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight; + AddIncomingSpill(page, range, page.FromRow, page.ToRow, page.FromColumn, page.ToColumn, originX, originY, isPrintTitle: false); + pdfPages.Page[i] = page; + } + return pdfPages; + } + + private static bool CellHasRightBorder(PdfCell cell) + { + var cs = cell?.CellStyle; if (cs == null) return false; + return (cs.xfRight != null && cs.xfRight.Style != ExcelBorderStyle.None) || (cs.dxfRight?.HasValue ?? false); + } + + private static bool CellHasLeftBorder(PdfCell cell) + { + var cs = cell?.CellStyle; if (cs == null) return false; + return (cs.xfLeft != null && cs.xfLeft.Style != ExcelBorderStyle.None) || (cs.dxfLeft?.HasValue ?? false); + } + + private static bool CellHasTopBorder(PdfCell cell) + { + var cs = cell?.CellStyle; if (cs == null) return false; + return (cs.xfTop != null && cs.xfTop.Style != ExcelBorderStyle.None) || (cs.dxfTop?.HasValue ?? false); + } + + private static bool CellHasBottomBorder(PdfCell cell) + { + var cs = cell?.CellStyle; if (cs == null) return false; + return (cs.xfBottom != null && cs.xfBottom.Style != ExcelBorderStyle.None) || (cs.dxfBottom?.HasValue ?? false); + } + + private static void EmitBandFrameH(List target, PdfRange range, double y, int row, int fromCol, int nc, double[] colX, Func hasBorder) + { + double? rs = null; double re = 0d; + for (int ci = 0; ci < nc; ci++) + { + double segL = colX[ci], segR = colX[ci + 1]; + if (segR - segL <= 0d) { if (rs != null) { target.Add(new GridLine(rs.Value, y, re, y)); rs = null; } continue; } + if (!hasBorder(RangeCell(range, row, fromCol + ci))) { if (rs == null) rs = segL; re = segR; } + else if (rs != null) { target.Add(new GridLine(rs.Value, y, re, y)); rs = null; } + } + if (rs != null) target.Add(new GridLine(rs.Value, y, re, y)); + } + + private static void EmitBandFrameV(List target, PdfRange range, double x, int col, int fromRow, int nr, double[] rowY, Func hasBorder) + { + double? rs = null; double re = 0d; + for (int ri = 0; ri < nr; ri++) + { + double segT = rowY[ri], segB = rowY[ri + 1]; + if (segT - segB <= 0d) { if (rs != null) { target.Add(new GridLine(x, rs.Value, x, re)); rs = null; } continue; } + if (!hasBorder(RangeCell(range, fromRow + ri, col))) { if (rs == null) rs = segT; re = segB; } + else if (rs != null) { target.Add(new GridLine(x, rs.Value, x, re)); rs = null; } + } + if (rs != null) target.Add(new GridLine(x, rs.Value, x, re)); + } + } +} diff --git a/src/EPPlus/Export/PdfExport/PdfCatalog.cs b/src/EPPlus/Export/PdfExport/PdfCatalog.cs new file mode 100644 index 0000000000..5b8cc13199 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/PdfCatalog.cs @@ -0,0 +1,381 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Graphics; +using EPPlus.Export.Pdf; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Resources; +using OfficeOpenXml.Export.PdfExport.Data; +using OfficeOpenXml.Export.PdfExport.Layout; +using OfficeOpenXml.Export.PdfExport.RowResize; +using OfficeOpenXml.Export.PdfExport.TextMapping; +using OfficeOpenXml.Export.PdfExport.TextShaping; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace OfficeOpenXml.Export.PdfExport +{ + internal class PdfCatalog + { + internal PdfDictionaries _dictionaries = new PdfDictionaries(); + private bool _addTextForHeadings = true; + + // + // CONSTRUCTORS FOR MULTIPLE WORKSHEETS AS INPUT + // + public PdfCatalog() { } + + public PdfCatalog(PdfPageSettings pageSettings, ExcelWorkbook workbook) + { + HandleWorksheetCollection(pageSettings, workbook.Worksheets.ToArray()); + } + + public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + { + HandleWorksheetCollection(pageSettings, worksheets); + } + + public PdfCatalog(PdfPageSettings pageSettings, List worksheets) + { + HandleWorksheetCollection(pageSettings, worksheets.ToArray()); + } + + private void HandleWorksheetCollection(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + { + var pdfSheets = GetPdfWorksheets(pageSettings, worksheets); + foreach (var pdfSheet in pdfSheets) + { + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + } + var Layout = GetLayout(pageSettings, pdfSheets); + //send Layout to pdf export here. + } + + // + // CONSTRUCTORS FOR SINGLE WORKSHEET AS INPUT + // + + public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet worksheet, string fileName) + { + BuildPdf(pageSettings, worksheet, fileName); + } + + //public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet worksheet, Stream stream) + //{ + // BuildPdf(pageSettings, worksheet); + //} + + private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, string fileName) + { + //pageSettings.defaultFontName = worksheet.Workbook.ThemeManager.CurrentTheme.FontScheme.MinorFont[0].Typeface; + pageSettings.defaultFontName = worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; + PdfWorksheet pdfSheet = null; + try + { + Stopwatch sw = Stopwatch.StartNew(); + + //Collect Text + pdfSheet = GetPdfWorksheet(pageSettings, worksheet); + sw.Stop(); + var CollectTextTime = sw.ElapsedMilliseconds; + sw.Reset(); + sw.Start(); + + //Shape Text + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + sw.Stop(); + var ShapeTextTime = sw.ElapsedMilliseconds; + sw.Reset(); + sw.Start(); + + //Auto-Fit Rows + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + sw.Stop(); + var AutoFitRowTime = sw.ElapsedMilliseconds; + sw.Reset(); + sw.Start(); + + //Create Layout + var layout = GetLayout(pageSettings, pdfSheet); + sw.Stop(); + var CreateLayoutTime = sw.ElapsedMilliseconds; + sw.Reset(); + sw.Start(); + + //Write Pdf Document + ExcelPdf excelPdf = new ExcelPdf(); + excelPdf.CreatePdf(pageSettings, _dictionaries, layout, fileName); + sw.Stop(); + var CreatePdfTime = sw.ElapsedMilliseconds; + sw.Reset(); + } + finally + { + //Clean up the temporary worksheet used to build the comments/notes pages, + //so the source workbook isn't permanently mutated by the PDF export. + if (pdfSheet != null && pdfSheet.CommentsAndNotesSheet != null) + { + worksheet.Workbook.Worksheets.Delete(pdfSheet.CommentsAndNotesSheet); + pdfSheet.CommentsAndNotesSheet = null; + } + } + } + + // + // CONSTRUCTORS FOR RANGE AS INPUT + // + + public PdfCatalog(PdfPageSettings pageSettings, ExcelRangeBase range) + { + PdfWorksheet pdfSheet = GetPdfWorksheet(pageSettings, range); + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + var Layout = GetLayout(pageSettings, pdfSheet); + //send Layout to pdf export here. + } + + internal PdfCellCollection GetCellCollectionFromRange(PdfPageSettings pageSettings, ExcelRangeBase range) + { + PdfWorksheet pdfSheet = GetPdfWorksheet(pageSettings, range); + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + return pdfSheet.Ranges[0].Map; + } + + + //Private Methods + + + //Create Layout Methods + + private Transform GetLayout(PdfPageSettings pageSettings, PdfWorksheet[] pdfSheets) + { + var Layout = PdfLayout.GetLayout(pageSettings, _dictionaries, pdfSheets); + return Layout; + } + + private Transform GetLayout(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + PdfWorksheet[] pdfSheets = new PdfWorksheet[1] { pdfSheet }; + var Layout = PdfLayout.GetLayout(pageSettings, _dictionaries, pdfSheets); + return Layout; + } + + //Shape Text Methods + + internal void ShapeTextInPdfWorksheet(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + // Pass 1: collect text per font + IterateCells(pdfSheet, cell => PdfTextShaper.CollectText(_dictionaries, cell)); + + // Pass 2: build one provider per font + foreach (var kvp in _dictionaries.Fonts) + { + _dictionaries.ShapedProviders[kvp.Key] = kvp.Value.fontSubsetManager.CreateSubsettedProvider(); + } + + // Pass 3: shape text using the pre-built providers + IterateCells(pdfSheet, cell => PdfTextShaper.ShapeText(pageSettings, _dictionaries, cell)); + } + + private void IterateCells(PdfWorksheet pdfSheet, System.Action action) + { + foreach (var range in pdfSheet.Ranges) + { + for (int i = range.Map.FromRow; i <= range.Map.ToRow; i++) + { + for (int j = range.Map.FromColumn; j <= range.Map.ToColumn; j++) + { + action(range.Map[i, j]); + } + } + } + + if (pdfSheet.CommentsAndNotes.Map != null) + { + for (int i = pdfSheet.CommentsAndNotes.Map.FromRow; i <= pdfSheet.CommentsAndNotes.Map.ToRow; i++) + { + for (int j = pdfSheet.CommentsAndNotes.Map.FromColumn; j <= pdfSheet.CommentsAndNotes.Map.ToColumn; j++) + { + action(pdfSheet.CommentsAndNotes.Map[i, j]); + } + } + } + } + + //Collect Text Methods + private PdfWorksheet[] GetPdfWorksheets(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + { + PdfWorksheet[] pdfSheets = new PdfWorksheet[worksheets.Length]; + for (int i = 0; i < pdfSheets.Length; i++) + { + pdfSheets[i] = GetPdfWorksheet(pageSettings, worksheets[i]); + } + return pdfSheets; + } + + internal PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelWorksheet worksheet) + { + PdfWorksheet pdfSheet = new PdfWorksheet(); + pdfSheet.Ranges = new List(); + pdfSheet.Worksheet = worksheet; + pdfSheet.Ranges = GetRanges(pdfSheet.Worksheet); + if (pageSettings.ShowHeadings && _addTextForHeadings) _dictionaries.AddFont(pageSettings, pdfSheet.NormalStyle.Style.Font.Name, pdfSheet.GetSubFamilyFromNormalStyle, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); + _addTextForHeadings = false; + GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges); + GetPrintTitles(pageSettings, pdfSheet); + GetHeaderFooter(pageSettings, pdfSheet); + GetCommentsAndNotes(pageSettings, pdfSheet); + return pdfSheet; + } + + private PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelRangeBase excelRange) + { + PdfWorksheet pdfSheet = new PdfWorksheet(); + pdfSheet.Ranges = new List(); + pdfSheet.Worksheet = excelRange.Worksheet; + pdfSheet.Ranges.Add(new PdfRange(excelRange, false)); + if (pageSettings.ShowHeadings && _addTextForHeadings) _dictionaries.AddFont(pageSettings, pdfSheet.NormalStyle.Style.Font.Name, pdfSheet.GetSubFamilyFromNormalStyle, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); + _addTextForHeadings = false; + pdfSheet.Ranges[0] = GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges[0]); + GetPrintTitles(pageSettings, pdfSheet); + GetHeaderFooter(pageSettings, pdfSheet); + GetCommentsAndNotes(pageSettings, pdfSheet); + return pdfSheet; + } + + private List GetRanges(ExcelWorksheet worksheet) + { + List ranges = new List(); + if (worksheet.Names.ContainsKey("_xlnm.Print_Area")) + { + for (int i = 0; i < worksheet.Names["_xlnm.Print_Area"].Addresses.Count; i++) + { + var range = worksheet.Cells[worksheet.Names["_xlnm.Print_Area"].Addresses[i].Address]; + ranges.Add(new PdfRange(range, false)); + } + } + else + { + var range = worksheet.DimensionByValue; + var pdfRange = new PdfRange(range, true); + pdfRange.ExtendColumns = true; + ranges.Add(pdfRange); + } + return ranges; + } + + private void GetMaps(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, List ranges) + { + for (int i = 0; i < ranges.Count; i++) + { + ranges[i] = GetMaps(pageSettings, pdfSheet, ranges[i]); + } + } + + private PdfRange GetMaps(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, PdfRange range) + { + var temp = range; + temp.Map = PdfTextMap.SetTextMap(pageSettings, _dictionaries, pdfSheet, ref temp); + range = temp; + return range; + } + + private void GetPrintTitles(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + var worksheet = pdfSheet.Worksheet; + // --- Step 1: auto-detect from the worksheet's _xlnm.Print_Titles defined name --- + if (worksheet.Names.ContainsKey("_xlnm.Print_Titles")) + { + var printTitlesName = worksheet.Names["_xlnm.Print_Titles"]; + foreach (var address in printTitlesName.Addresses) + { + // A full-row reference spans every column (e.g. $1:$3 → _toCol == MaxColumns) + if (address._toCol >= ExcelPackage.MaxColumns) + { + pdfSheet.PrintTitleRowFrom = address._fromRow; + pdfSheet.PrintTitleRowTo = address._toRow; + } + // A full-column reference spans every row (e.g. $A:$B → _toRow == MaxRows) + else if (address._toRow >= ExcelPackage.MaxRows) + { + pdfSheet.PrintTitleColFrom = address._fromCol; + pdfSheet.PrintTitleColTo = address._toCol; + } + } + } + // --- Step 2: PdfPageSettings overrides take precedence over the defined name --- + if (pageSettings.RowsToRepeatAtTop != null) + { + ExcelAddressBase repeatRows = new ExcelAddressBase(pageSettings.RowsToRepeatAtTop); + pdfSheet.PrintTitleRowFrom = repeatRows._fromRow; + pdfSheet.PrintTitleRowTo = repeatRows._toRow; + } + if (pageSettings.ColumnsToRepeatAtLeft != null) + { + ExcelAddressBase repeatCols = new ExcelAddressBase(pageSettings.ColumnsToRepeatAtLeft); + pdfSheet.PrintTitleColFrom = repeatCols._fromCol; + pdfSheet.PrintTitleColTo = repeatCols._toCol; + } + + // --- Step 3: mark cells so the renderer can identify them instantly --- + foreach (var range in pdfSheet.Ranges) + MarkPrintTitleCells(pdfSheet, range); + } + + private static void MarkPrintTitleCells(PdfWorksheet pdfSheet, PdfRange range) + { + var map = range.Map; + + for (int row = map.FromRow; row <= map.ToRow; row++) + { + bool isTitleRow = pdfSheet.PrintTitleRowFrom >= 0 + && row >= pdfSheet.PrintTitleRowFrom + && row <= pdfSheet.PrintTitleRowTo; + + for (int col = map.FromColumn; col <= map.ToColumn; col++) + { + bool isTitleCol = pdfSheet.PrintTitleColFrom >= 0 + && col >= pdfSheet.PrintTitleColFrom + && col <= pdfSheet.PrintTitleColTo; + + if (!isTitleRow && !isTitleCol) continue; + + var cell = map[row, col]; + if (cell == null) continue; + + if (isTitleRow) cell.IsPrintTitleRow = true; + if (isTitleCol) cell.IsPrintTitleCol = true; + } + } + } + + private void GetHeaderFooter(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + pdfSheet.HeaderFooters = new PdfHeaderFooterCollection(pageSettings, _dictionaries, pdfSheet, pdfSheet.Worksheet.HeaderFooter); + } + + private void GetCommentsAndNotes(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + if (pageSettings.CommentsAndNotes == CommentsAndNotes.AtEndOfSheet && pdfSheet.CommentsAndNotesCollections.Count > 0) + { + var cnPageSettings = new PdfPageSettings(); + cnPageSettings.CommentsAndNotes = CommentsAndNotes.None; + cnPageSettings.ShowHeadings = false; + pdfSheet.CommentsAndNotesSheet = PdfCommentsAndNotes.CreateCommentAndNotesPages(pdfSheet.CommentsAndNotesCollections, pdfSheet.Worksheet); + pdfSheet.CommentsAndNotes = new PdfRange(pdfSheet.CommentsAndNotesSheet.Dimension, false); + pdfSheet.CommentsAndNotes = GetMaps(cnPageSettings, pdfSheet, pdfSheet.CommentsAndNotes); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Export/PdfExport/RowResize/PdfCalculateRowHeight.cs b/src/EPPlus/Export/PdfExport/RowResize/PdfCalculateRowHeight.cs new file mode 100644 index 0000000000..0d1421fd8e --- /dev/null +++ b/src/EPPlus/Export/PdfExport/RowResize/PdfCalculateRowHeight.cs @@ -0,0 +1,92 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Export.PdfExport.Data; + +namespace OfficeOpenXml.Export.PdfExport.RowResize +{ + internal class PdfCalculateRowHeight + { + public static void ResizeRowHeights(PdfWorksheet pdfSheet) + { + for (int r = 0; r < pdfSheet.Ranges.Count; r++) + { + var range = pdfSheet.Ranges[r]; + ResizeRange(ref range); + pdfSheet.Ranges[r] = range; + } + if (pdfSheet.CommentsAndNotes.Map != null) + { + var cnRange = pdfSheet.CommentsAndNotes; + ResizeRange(ref cnRange); + pdfSheet.CommentsAndNotes = cnRange; + } + } + + public static void ResizeRange(ref PdfRange range) + { + double newTotalHeight = 0d; + for (int rowIdx = 0; rowIdx < range.RowHeights.Count; rowIdx++) + { + var rowHeight = range.RowHeights[rowIdx]; + if (rowHeight.Height == 0d) + continue; + + if (!rowHeight.UsesDefaultValue) + { + newTotalHeight += rowHeight.Height; + continue; + } + int row = range.Range._fromRow + rowIdx; + double maxRequired = rowHeight.Height; + bool hasWrappedCell = false; + for (int colIdx = 0; colIdx < range.ColWidths.Count; colIdx++) + { + int col = range.Range._fromCol + colIdx; + var cell = range.Map[row, col]; + if (cell == null || cell.Hidden) + continue; + if (cell.Merged) + continue; + if (cell.ContentAligmnet.ShrinkToFit) + continue; + if (!cell.ContentAligmnet.WrapText) + continue; + if (cell.TextLines == null || cell.TextLines.Count == 0) + continue; + + hasWrappedCell = true; + double required = GetRequiredHeightFromLines(cell); + if (required > maxRequired) + maxRequired = required; + } + if (hasWrappedCell) + { + rowHeight.Height = maxRequired; + range.RowHeights[rowIdx] = rowHeight; + } + newTotalHeight += rowHeight.Height; + } + range.TotalHeight = newTotalHeight; + } + + private static double GetRequiredHeightFromLines(PdfCell cell) + { + double total = 0d; + foreach (var line in cell.TextLines) + { + total += line.LargestAscent + line.LargestDescent; + } + return total; + } + } +} diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfCommentsAndNotes.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfCommentsAndNotes.cs new file mode 100644 index 0000000000..defb31548d --- /dev/null +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfCommentsAndNotes.cs @@ -0,0 +1,116 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.ThreadedComments; +using System.Collections.Generic; + +namespace OfficeOpenXml.Export.PdfExport +{ + internal class PdfCommentsAndNotes + { + public ExcelComment Comment; + public ExcelThreadedCommentThread ThreadedComment; + public static bool HasThreadedComment = false; + + public PdfCommentsAndNotes(ExcelComment comment) + { + Comment = comment; + } + + public PdfCommentsAndNotes(ExcelThreadedCommentThread tComment) + { + ThreadedComment = tComment; + } + + public static ExcelWorksheet CreateCommentAndNotesPages(Dictionary CommentsAndNotesCollections, ExcelWorksheet ws) + { + var ns = ws.Workbook.Styles.GetNormalStyle(); + var tempWS = ws.Workbook.Worksheets.Add("TemporaryWorksheetForCommentsInPdfExporterForEPPlus"); + int row = 1; + int col = 1; + tempWS.Column(col).Width = 10d; + tempWS.Column(col + 1).Width = 75d; + foreach (var commentNote in CommentsAndNotesCollections) + { + AddText(tempWS, row, col, "Cell:", true, ExcelHorizontalAlignment.Right, ExcelVerticalAlignment.Bottom, ns); + AddText(tempWS, row, col + 1, commentNote.Key, false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Bottom, ns); + row++; + if (commentNote.Value.ThreadedComment != null) + { + var CommentReply = "Comment:"; + foreach (var comment in commentNote.Value.ThreadedComment.Comments) + { + AddText(tempWS, row, col, CommentReply, true, ExcelHorizontalAlignment.Right, ExcelVerticalAlignment.Bottom, ns); + AddText(tempWS, row, col + 1, comment.Author.DisplayName, false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Bottom, ns); + row++; + AddText(tempWS, row, col + 1, comment.Text, false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Top, ns); + row++; + AddText(tempWS, row, col + 1, comment.DateCreated.ToString("yyyy-MM-dd HH:mm"), false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Bottom, ns); + row++; + CommentReply = "Reply:"; + } + } + else if (commentNote.Value.Comment != null) + { + var note = commentNote.Value.Comment; + AddText(tempWS, row, col, "Note:", true, ExcelHorizontalAlignment.Right, ExcelVerticalAlignment.Bottom, ns); + AddText(tempWS, row, col + 1, note.Author, false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Bottom, ns); + row++; + AddText(tempWS, row, col + 1, note.RichText, false, ExcelHorizontalAlignment.Left, ExcelVerticalAlignment.Bottom, ns); + row++; + } + row++; + } + return tempWS; + } + private static void AddText(ExcelWorksheet ws, int row, int col, string text, bool bold, ExcelHorizontalAlignment horizontalAlignment, ExcelVerticalAlignment verticalAlignment, ExcelNamedStyleXml ns) + { + var cell = ws.Cells[row, col]; + cell.RichText.Clear(); + var rt = cell.RichText.Add(text); + rt.Bold = bold; + rt.FontName = ns.Style.Font.Name; + rt.Family = ns.Style.Font.Family; + rt.Size = ns.Style.Font.Size; + cell.Style.HorizontalAlignment = horizontalAlignment; + cell.Style.VerticalAlignment = verticalAlignment; + cell.Style.WrapText = true; + } + + private static void AddText(ExcelWorksheet ws, int row, int col, ExcelRichTextCollection RichText, bool bold, ExcelHorizontalAlignment horizontalAlignment, ExcelVerticalAlignment verticalAlignment, ExcelNamedStyleXml ns) + { + var cell = ws.Cells[row, col]; + cell.RichText.Clear(); + for (int i = 1; i < RichText.Count; i++) + { + var rt = RichText[i]; + var trimmedText = rt.Text.Trim(); + var r = cell.RichText.Add(trimmedText); + r.Bold = rt.Bold; + r.Italic = rt.Italic; + r.Color = rt.Color; + r.ColorSettings = rt.ColorSettings; + r.Strike = rt.Strike; + r.UnderLine = rt.UnderLine; + r.UnderLineType = rt.UnderLineType; + r.FontName = rt.FontName; + r.Family = rt.Family; + r.Size = rt.Size; + } + cell.Style.HorizontalAlignment = horizontalAlignment; + cell.Style.VerticalAlignment = verticalAlignment; + cell.Style.WrapText = true; + } + } +} diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs new file mode 100644 index 0000000000..0f6e9be031 --- /dev/null +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs @@ -0,0 +1,165 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Resources; +using OfficeOpenXml.Export.PdfExport.Data; +using System.Collections.Generic; +using System.Linq; + +namespace OfficeOpenXml.Export.PdfExport.TextMapping +{ + internal class PdfHeaderFooterCollection + { + public List PdfHeaderFooterEntries = new List(); + public bool ScaleWithDocument = false; + public bool AlignWithMargins = false; + + public PdfHeaderFooterCollection(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfWorksheet pdfSheet, ExcelHeaderFooter headerFooter) + { + bool differentFirst = pdfSheet.Worksheet.HeaderFooter.differentFirst; + bool differentOddEven = pdfSheet.Worksheet.HeaderFooter.differentOddEven; + bool AlignWithMargins = pdfSheet.Worksheet.HeaderFooter.AlignWithMargins; + bool ScaleWithDocument = pdfSheet.Worksheet.HeaderFooter.ScaleWithDocument; + PdfHeaderFooter entry = null; + if (differentFirst) + { + //First Header + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstHeader.LeftAligned, HeaderFooterType.First, HeaderFooterAlignment.Left, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstHeader.Centered, HeaderFooterType.First, HeaderFooterAlignment.Center, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstHeader.RightAligned, HeaderFooterType.First, HeaderFooterAlignment.Right, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + //First Footer + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstFooter.LeftAligned, HeaderFooterType.First, HeaderFooterAlignment.Left, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstFooter.Centered, HeaderFooterType.First, HeaderFooterAlignment.Center, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.FirstFooter.RightAligned, HeaderFooterType.First, HeaderFooterAlignment.Right, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + } + if (differentOddEven) + { + //Even Header + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenHeader.LeftAligned, HeaderFooterType.Even, HeaderFooterAlignment.Left, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenHeader.Centered, HeaderFooterType.Even, HeaderFooterAlignment.Center, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenHeader.RightAligned, HeaderFooterType.Even, HeaderFooterAlignment.Right, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + //Even Footer + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenFooter.LeftAligned, HeaderFooterType.Even, HeaderFooterAlignment.Left, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenFooter.Centered, HeaderFooterType.Even, HeaderFooterAlignment.Center, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.EvenFooter.RightAligned, HeaderFooterType.Even, HeaderFooterAlignment.Right, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + } + //Odd Header + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddHeader.LeftAligned, HeaderFooterType.Odd, HeaderFooterAlignment.Left, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddHeader.Centered, HeaderFooterType.Odd, HeaderFooterAlignment.Center, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddHeader.RightAligned, HeaderFooterType.Odd, HeaderFooterAlignment.Right, HeaderFooterSection.Header); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + //Odd Footer + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddFooter.LeftAligned, HeaderFooterType.Odd, HeaderFooterAlignment.Left, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddFooter.Centered, HeaderFooterType.Odd, HeaderFooterAlignment.Center, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + entry = PdfTextMap.GetTextFormats(pageSettings, dictionaries, pdfSheet.Worksheet, headerFooter.OddFooter.RightAligned, HeaderFooterType.Odd, HeaderFooterAlignment.Right, HeaderFooterSection.Footer); + if (entry != null) + { + entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); + PdfHeaderFooterEntries.Add(entry); + } + } + + public PdfHeaderFooter Get(HeaderFooterType type, HeaderFooterSection section, HeaderFooterAlignment alignment) + { + return PdfHeaderFooterEntries.FirstOrDefault(e => + e.PageType == type && + e.Section == section && + e.Alignment == alignment); + } + } +} diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs new file mode 100644 index 0000000000..e09939f34b --- /dev/null +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs @@ -0,0 +1,1031 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Layout; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using EPPlus.Graphics.Units; +using OfficeOpenXml.Export.PdfExport.Data; +using OfficeOpenXml.Interfaces.Fonts; +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.Dxf; +using OfficeOpenXml.Style.HeaderFooterTextFormat; +using OfficeOpenXml.Style.Table; +using OfficeOpenXml.Table; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OfficeOpenXml.Export.PdfExport.TextMapping +{ + internal class PdfTextMap + { + public static PdfCellCollection SetTextMap(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfWorksheet pdfSheet, ref PdfRange pdfRange) + { + var Range = pdfRange; + var worksheet = Range.Range.Worksheet; + var ZeroCharWidth = pdfSheet.ZeroCharWidth = PdfWorksheet.GetThemeFont0Width(worksheet); + int addedColumns = Range.ExtendColumns ? AddColumnsForNonWrappedText(pageSettings, worksheet, pdfSheet) : 0; + var Map = new PdfCellCollection(Range.Range._fromRow, Range.Range._toRow, Range.Range._fromCol, Range.Range._toCol + addedColumns); + pdfSheet.ToRow = pdfSheet.ToRow < Range.Range._toRow ? Range.Range._toRow : pdfSheet.ToRow; + bool firstColumnRun = true; + List checkedMergedCells = new List(); + for (int row = Range.Range._fromRow; row <= Range.Range._toRow; row++) + { + var hiddenRow = worksheet.Row(row).Hidden; + var r = (RowInternal)worksheet.GetValueInner(row, 0); + bool usesDefaultValue = false; + double height = 0; + if (r == null || r.Height < 0) + { + usesDefaultValue = true; + height = worksheet.DefaultRowHeight; + } + else + { + height = UnitConversion.ExcelRowHeightToPoints(r.Height); + } + Range.TotalHeight += hiddenRow ? 0d : height; + Range.RowHeights.Add(new RowHeight { Height = hiddenRow ? 0d : height, UsesDefaultValue = usesDefaultValue }); + for (int col = Range.Range._fromCol; col <= Range.Range._toCol + addedColumns; col++) + { + var hiddenCol = worksheet.Column(col).Hidden; + var width = UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(col).Width, ZeroCharWidth); + if (firstColumnRun) + { + Range.TotalWidth += hiddenCol ? 0d : width; + Range.ColWidths.Add(hiddenCol ? 0d : width); + } + var tempMap = new PdfCell(); + tempMap.Hidden = hiddenRow || hiddenCol; + tempMap.ColumnWidth = tempMap.Width = hiddenCol ? 0d : width; + var cell = worksheet.Cells[row, col]; + tempMap.Name = cell.Address; + if (cell.Merge) + { + HandleMergedCell(pageSettings, dictionaries, cell, checkedMergedCells, Map, tempMap, pdfSheet.ZeroCharWidth); + } + var cellStyle = new PdfCellStyle(); + GetBorderStyles(cell, cellStyle, tempMap); + if (tempMap.Main == null) + { + GetFillStyles(cell, cellStyle); + GetFontStyle(cell, cellStyle); + tempMap.ContentAligmnet = GetContentAlignment(cell); + if (!string.IsNullOrEmpty(cell.Text)) + { + tempMap.Text = cell.Text; + tempMap.TextFragments = GetTextFragments(pageSettings, dictionaries, cell, cellStyle); + } + } + tempMap.CellStyle = cellStyle; + Map[row, col] = tempMap; + if (pageSettings.CommentsAndNotes != CommentsAndNotes.None) + { + if (cell.Comment != null && cell.ThreadedComment == null) + { + pdfSheet.CommentsAndNotesCollections.Add(cell.Address, new PdfCommentsAndNotes(cell.Comment)); + } + if (cell.ThreadedComment != null) + { + pdfSheet.CommentsAndNotesCollections.Add(cell.Address, new PdfCommentsAndNotes(cell.ThreadedComment)); + PdfCommentsAndNotes.HasThreadedComment = true; + } + } + } + firstColumnRun = false; + } + worksheet.ConditionalFormatting.ClearTempExportCacheForAllCFs(); + pdfRange = Range; + return Map; + } + + private static void HandleMergedCell(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRange cell, List checkedMergedCells, PdfCellCollection map, PdfCell tempMap, double ZeroCharWidth) + { + var worksheet = cell.Worksheet; + string mergeAddress = worksheet.MergedCells[cell.Start.Row, cell.Start.Column]; + ExcelAddressBase address = new ExcelAddressBase(mergeAddress); + if (!checkedMergedCells.Contains(mergeAddress)) + { + double totalWidth = 0, totalHeight = 0; + for (int k = address._fromRow; k <= address._toRow; k++) + { + totalHeight += UnitConversion.ExcelRowHeightToPoints(worksheet.Row(k).Height); + } + for (int l = address._fromCol; l <= address._toCol; l++) + { + totalWidth += UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(l).Width, ZeroCharWidth); + } + checkedMergedCells.Add(mergeAddress); + tempMap.Width = totalWidth; + tempMap.Height = totalHeight; + tempMap.Main = null; + } + else + { + tempMap.Main = map[address._fromRow, address._fromCol]; + if (tempMap.Main == null) + { + var main = worksheet.Cells[address._fromRow, address._fromCol]; + PdfCell mainCell = new PdfCell(); + var cellStyle = new PdfCellStyle(); + GetBorderStyles(main, cellStyle, mainCell); + GetFillStyles(main, cellStyle); + GetFontStyle(main, cellStyle); + mainCell.ContentAligmnet = GetContentAlignment(main); + if (!string.IsNullOrEmpty(main.Text)) + { + mainCell.Text = main.Text; + mainCell.TextFragments = GetTextFragments(pageSettings, dictionaries, main, cellStyle); + } + mainCell.CellStyle = cellStyle; + tempMap.Main = mainCell; + } + } + tempMap.MergedAddress = address; + tempMap.Name = tempMap.Name + " ; " + address.ToString(); + tempMap.Merged = true; + } + + private static void GetFillStyles(ExcelRangeBase cell, PdfCellStyle cellStyle) + { + if (cell.Style.Fill.IsEmpty()) + { + //Conditional Formating + var cf = cell.ConditionalFormatting.GetConditionalFormattings(); + if (cf != null && cf.Count > 0) + { + // Sort ascending — priority 1 beats priority 2, etc. + var ordered = cf.OrderBy(r => r.Priority); + foreach (var rule in ordered) + { + // Use the core per-rule evaluator (the same one the HTML exporter + // calls). It correctly handles every rule type — comparisons, text, + // blanks/errors, top/bottom, above/below average, duplicate/unique, + // time periods and formula expressions — including the range-wide + // aggregates, which the previous hand-rolled evaluator stubbed out. + if (!rule.ShouldApplyToCell(cell)) + { + if (rule.StopIfTrue) break; // higher-priority rule fired but had no fill — stop anyway + continue; + } + + if (rule.Style?.Fill != null && rule.Style.Fill.HasValue) + { + cellStyle.dxfFill = rule.Style.Fill; + // xfFill must be non-null for the downstream dxf path + // (PdfCellLayout checks xfFill.IsEmpty()); the cell's own fill + // is empty here, which is exactly what selects the dxf fill. + cellStyle.xfFill = cell.Style.Fill; + return; // CF fill wins — skip table and xf entirely + } + + if (rule.StopIfTrue) break; + } + } + //Table + var tables = cell.Worksheet.Tables.GetIntersectingRanges(cell); + if (tables.Count > 0) + { + var table = tables[0].Value; + var range = table.Range; + int tableRow = 0; + int tableCol = 0; + ExcelTableNamedStyle tableStyle; + if (table.TableStyle == TableStyles.Custom) + { + tableStyle = cell.Worksheet.Workbook.Styles.TableStyles[table.StyleName].As.TableStyle; + } + else + { + var tmpNode = table.WorkSheet.Workbook.StylesXml.CreateElement("c:tableStyle"); + tableStyle = new ExcelTableNamedStyle(cell.Worksheet.Workbook.Styles.NameSpaceManager, tmpNode, cell.Worksheet.Workbook.Styles); + tableStyle.SetFromTemplate((TableStyles)table.TableStyle); + } + tableRow = cell._fromRow - range._fromRow; + tableCol = cell._fromCol - range._fromCol; + if (table.ShowHeader && tableRow == 0) + { + cellStyle.dxfFill = tableStyle.HeaderRow.Style.Fill; + } + else if (table.ShowTotal && range._toRow == cell._fromRow) + { + cellStyle.dxfFill = tableStyle.TotalRow.Style.Fill; + } + else if (table.ShowFirstColumn && tableCol == 0) + { + cellStyle.dxfFill = tableStyle.FirstColumn.Style.Fill; + } + else if (table.ShowLastColumn && range._toCol == cell._fromCol) + { + cellStyle.dxfFill = tableStyle.LastColumn.Style.Fill; + } + else if (table.ShowRowStripes) + { + cellStyle.dxfFill = (tableRow & 1) == 0 ? tableStyle.SecondRowStripe.Style.Fill : tableStyle.FirstRowStripe.Style.Fill; + } + else if (table.ShowColumnStripes) + { + cellStyle.dxfFill = (tableCol & 1) != 0 ? tableStyle.SecondColumnStripe.Style.Fill : tableStyle.FirstColumnStripe.Style.Fill; + } + else + { + cellStyle.dxfFill = tableStyle.WholeTable.Style.Fill; + } + } + } + cellStyle.xfFill = cell.Style.Fill; + } + + private static void GetBorderStyles(ExcelRangeBase cell, PdfCellStyle cellStyle, PdfCell pcell) + { + if (cell != null) + { + cellStyle.xfTop = cell.Style.Border.Top; + cellStyle.xfBottom = cell.Style.Border.Bottom; + cellStyle.xfLeft = cell.Style.Border.Left; + cellStyle.xfRight = cell.Style.Border.Right; + if (pcell.Main == null) + { + cellStyle.Diagonal = cell.Style.Border.Diagonal; + cellStyle.DiagonalUp = cell.Style.Border.DiagonalUp; + cellStyle.DiagonalDown = cell.Style.Border.DiagonalDown; + } + else + { + cellStyle.Diagonal = cell.Style.Border.Diagonal; + cellStyle.DiagonalUp = false; + cellStyle.DiagonalDown = false; + } + var tables = cell.Worksheet.Tables.GetIntersectingRanges(cell); + if (tables.Count > 0) + { + var table = tables[0].Value; + ExcelTableNamedStyle tableStyle; + if (table.TableStyle == TableStyles.Custom) + { + tableStyle = cell.Worksheet.Workbook.Styles.TableStyles[table.StyleName].As.TableStyle; + } + else + { + var tmpNode = table.WorkSheet.Workbook.StylesXml.CreateElement("c:tableStyle"); + tableStyle = new ExcelTableNamedStyle(cell.Worksheet.Workbook.Styles.NameSpaceManager, tmpNode, cell.Worksheet.Workbook.Styles); + tableStyle.SetFromTemplate((TableStyles)table.TableStyle); + } + cellStyle.dxfTop = GetTopBorderItem(cell, cellStyle.xfTop, table, tableStyle); + cellStyle.dxfBottom = GetBottomBorderItem(cell, cellStyle.xfBottom, table, tableStyle); + cellStyle.dxfLeft = GetLeftBorderItem(cell, cellStyle.xfLeft, table, tableStyle); + cellStyle.dxfRight = GetRightBorderItem(cell, cellStyle.xfRight, table, tableStyle); + } + var cfBorder = GetConditionalFormattingBorder(cell); + if (cfBorder != null) + { + if (cfBorder.Top != null && cfBorder.Top.HasValue) cellStyle.dxfTop = cfBorder.Top; + if (cfBorder.Bottom != null && cfBorder.Bottom.HasValue) cellStyle.dxfBottom = cfBorder.Bottom; + if (cfBorder.Left != null && cfBorder.Left.HasValue) cellStyle.dxfLeft = cfBorder.Left; + if (cfBorder.Right != null && cfBorder.Right.HasValue) cellStyle.dxfRight = cfBorder.Right; + } + } + } + + private static ExcelDxfBorderBase GetConditionalFormattingBorder(ExcelRangeBase cell) + { + var cf = cell.ConditionalFormatting.GetConditionalFormattings(); + if (cf != null && cf.Count > 0) + { + var ordered = cf.OrderBy(r => r.Priority); + foreach (var rule in ordered) + { + if (!rule.ShouldApplyToCell(cell)) + { + if (rule.StopIfTrue) break; + continue; + } + if (rule.Style?.Border != null && rule.Style.Border.HasValue) + { + return rule.Style.Border; + } + if (rule.StopIfTrue) break; + } + } + return null; + } + + private static PdfCellStyle GetFontStyle(ExcelRangeBase cell, PdfCellStyle cellStyle) + { + var cf = cell.ConditionalFormatting.GetConditionalFormattings(); + if (cf != null && cf.Count > 0) + { + // Sort ascending — priority 1 beats priority 2, etc. + var ordered = cf.OrderBy(r => r.Priority); + foreach (var rule in ordered) + { + if (!rule.ShouldApplyToCell(cell)) + { + if (rule.StopIfTrue) break; + continue; + } + if (rule.Style?.Font != null && rule.Style.Font.HasValue) + { + cellStyle.dxfFont = rule.Style.Font; + return cellStyle; // CF font wins over the table font + } + if (rule.StopIfTrue) break; + } + } + var tables = cell.Worksheet.Tables.GetIntersectingRanges(cell); + if (tables.Count > 0) + { + var table = tables[0].Value; + var range = table.Range; + ExcelTableNamedStyle tableStyle; + if (table.TableStyle == TableStyles.Custom) + { + tableStyle = cell.Worksheet.Workbook.Styles.TableStyles[table.StyleName].As.TableStyle; + } + else + { + var tmpNode = table.WorkSheet.Workbook.StylesXml.CreateElement("c:tableStyle"); + tableStyle = new ExcelTableNamedStyle(cell.Worksheet.Workbook.Styles.NameSpaceManager, tmpNode, cell.Worksheet.Workbook.Styles); + tableStyle.SetFromTemplate((TableStyles)table.TableStyle); + } + int tableRow = cell._fromRow - range._fromRow; + int tableCol = cell._fromCol - range._fromCol; + var font = tableStyle.WholeTable.Style.Font; + if (table.ShowHeader && tableRow == 0) + { + if (tableStyle.HeaderRow.Style.Font.HasValue) + { + font = tableStyle.HeaderRow.Style.Font; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstHeaderCell.Style.Font.HasValue) + { + font = tableStyle.FirstHeaderCell.Style.Font; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastHeaderCell.Style.Font.HasValue) + { + font = tableStyle.LastHeaderCell.Style.Font; + } + } + else if (table.ShowTotal && cell._fromRow == range._toRow) + { + if (tableStyle.TotalRow.Style.Font.HasValue) + { + font = tableStyle.TotalRow.Style.Font; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstTotalCell.Style.Font.HasValue) + { + font = tableStyle.FirstTotalCell.Style.Font; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastTotalCell.Style.Font.HasValue) + { + font = tableStyle.LastTotalCell.Style.Font; + } + } + else + { + if (table.ShowColumnStripes && (tableCol & 1) == 0) + { + font = tableStyle.FirstColumnStripe.Style.Font; + } + if (table.ShowColumnStripes && tableStyle.SecondColumnStripe.Style.Border.Top.HasValue && (tableCol & 1) != 0) + { + font = tableStyle.SecondColumnStripe.Style.Font; + } + if (table.ShowRowStripes && tableStyle.FirstRowStripe.Style.Font.HasValue && (tableRow & 1) != 0) + { + font = tableStyle.FirstRowStripe.Style.Font; + } + if (table.ShowRowStripes && tableStyle.SecondRowStripe.Style.Font.HasValue && (tableRow & 1) == 0) + { + font = tableStyle.SecondRowStripe.Style.Font; + } + if (table.ShowLastColumn && tableStyle.LastColumn.Style.Font.HasValue && cell._fromCol == range._toCol) + { + font = tableStyle.LastColumn.Style.Font; + } + if (table.ShowFirstColumn && tableStyle.FirstColumn.Style.Font.HasValue && tableCol == range._toCol) + { + font = tableStyle.FirstColumn.Style.Font; + } + } + cellStyle.dxfFont = font; + } + return cellStyle; + } + + private static PdfCellAlignmentData GetContentAlignment(ExcelRangeBase cell) + { + var contentAlignment = new PdfCellAlignmentData(); + contentAlignment.HorizontalAlignment = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)cell.Style.HorizontalAlignment; + contentAlignment.VerticalAlignment = (EPPlus.Export.Pdf.Enums.ExcelVerticalAlignment)cell.Style.VerticalAlignment; + contentAlignment.Indent = cell.Style.Indent; + contentAlignment.WrapText = cell.Style.WrapText; + contentAlignment.ShrinkToFit = cell.Style.ShrinkToFit; + contentAlignment.TextRotation = (cell.Style.TextRotation > 90) ? ((cell.Style.TextRotation == 255) ? 0 : 90 - cell.Style.TextRotation) : cell.Style.TextRotation; + contentAlignment.IsVertical = cell.Style.TextRotation == 255 ? true : false; + contentAlignment.TextDirection = (EPPlus.Export.Pdf.Enums.ExcelReadingOrder)cell.Style.ReadingOrder; + return contentAlignment; + } + + private static List GetTextFragments(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyle cellStyle) + { + bool dxfBold, dxfItalic, dxfStrike, dxfUnderline; + ExcelUnderLineType dxfUnderLineType; + System.Drawing.Color? dxfColor; + ReadDxfFontOverrides(cellStyle, out dxfBold, out dxfItalic, out dxfStrike, out dxfUnderline, out dxfUnderLineType, out dxfColor); + string forcedText = ResolveErrorText(pageSettings, cell); + if (cell.IsRichText) + { + return GetTextFragmentsFromRichText(pageSettings, dictionaries, cell.RichText, forcedText, + dxfBold, dxfItalic, dxfStrike, dxfUnderline, dxfUnderLineType, dxfColor); + } + return GetTextFragmentsFromCellStyle(pageSettings, dictionaries, cell, forcedText, + dxfBold, dxfItalic, dxfStrike, dxfUnderline, dxfUnderLineType, dxfColor); + } + + private static List GetTextFragmentsFromRichText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRichTextCollection richText, string forcedText, + bool dxfBold, bool dxfItalic, bool dxfStrike, bool dxfUnderline, ExcelUnderLineType dxfUnderLineType, System.Drawing.Color? dxfColor) + { + var textFragments = new List(richText.Count); + for (int i = 0; i < richText.Count; i++) + { + var rt = richText[i]; + var textFrag = new TextFragment(); + textFrag.Font = new RichTextFormatSimple(); + textFrag.Text = forcedText == null ? rt.Text : forcedText; + textFrag.Font.Family = rt.FontName; + textFrag.Font.Size = rt.Size; + textFrag.RichTextOptions.Bold = rt.Bold || dxfBold; + textFrag.RichTextOptions.Italic = rt.Italic || dxfItalic; + textFrag.RichTextOptions.UnderlineType = MapUnderlineType(rt.UnderLineType); + textFrag.RichTextOptions.StrikeType = (rt.Strike || dxfStrike) ? 2 : 1; + textFrag.RichTextOptions.SuperScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Superscript; + textFrag.RichTextOptions.SubScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Subscript; + textFrag.RichTextOptions.FontColor = dxfColor ?? rt.Color; + textFrag.Font.SubFamily = ComputeFontStyle(textFrag); + textFragments.Add(textFrag); + dictionaries.AddFont(pageSettings, textFrag.Font.Family, textFrag.Font.SubFamily, textFrag.Text); + } + return textFragments; + } + + private static List GetTextFragmentsFromCellStyle(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, string forcedText, + bool dxfBold, bool dxfItalic, bool dxfStrike, bool dxfUnderline, ExcelUnderLineType dxfUnderLineType, System.Drawing.Color? dxfColor) + { + var font = cell.Style.Font; + var textFragments = new List(1); + var textFrag = new TextFragment(); + textFrag.Font = new RichTextFormatSimple(); + textFrag.Text = forcedText == null ? cell.Text : forcedText; + textFrag.Font.Family = font.Name; + textFrag.Font.Size = font.Size; + textFrag.RichTextOptions.Bold = font.Bold || dxfBold; + textFrag.RichTextOptions.Italic = font.Italic || dxfItalic; + // Cell-style underline; dxf overrides only when the cell itself is not underlined. + ExcelUnderLineType underLineType; + if (font.UnderLine) + { + underLineType = font.UnderLineType == ExcelUnderLineType.None ? ExcelUnderLineType.Single : font.UnderLineType; + } + else if (dxfUnderline) + { + underLineType = dxfUnderLineType; + } + else + { + underLineType = ExcelUnderLineType.None; + } + textFrag.RichTextOptions.UnderlineType = MapUnderlineType(underLineType); + textFrag.RichTextOptions.StrikeType = (font.Strike || dxfStrike) ? 2 : 1; + textFrag.RichTextOptions.SuperScript = font.VerticalAlign == ExcelVerticalAlignmentFont.Superscript; + textFrag.RichTextOptions.SubScript = font.VerticalAlign == ExcelVerticalAlignmentFont.Subscript; + textFrag.RichTextOptions.FontColor = dxfColor ?? font.Color.ToColor(); + textFrag.Font.SubFamily = ComputeFontStyle(textFrag); + textFragments.Add(textFrag); + dictionaries.AddFont(pageSettings, textFrag.Font.Family, textFrag.Font.SubFamily, textFrag.Text); + return textFragments; + } + + private static void ReadDxfFontOverrides(PdfCellStyle cellStyle, out bool bold, out bool italic, out bool strike, out bool underline, out ExcelUnderLineType underLineType, out System.Drawing.Color? color) + { + bold = false; + italic = false; + strike = false; + underline = false; + underLineType = ExcelUnderLineType.None; + color = null; + if (cellStyle != null && cellStyle.dxfFont != null) + { + bold = cellStyle.dxfFont.Bold != null ? (bool)cellStyle.dxfFont.Bold : false; + italic = cellStyle.dxfFont.Italic != null ? (bool)cellStyle.dxfFont.Italic : false; + strike = cellStyle.dxfFont.Strike != null ? (bool)cellStyle.dxfFont.Strike : false; + underline = cellStyle.dxfFont.Underline != null; + underLineType = cellStyle.dxfFont.Underline != null ? (ExcelUnderLineType)cellStyle.dxfFont.Underline : ExcelUnderLineType.None; + if (cellStyle.dxfFont.Color != null && cellStyle.dxfFont.Color.HasValue) + { + color = cellStyle.dxfFont.Color.GetColorAsColor(); + } + } + } + + private static string ResolveErrorText(PdfPageSettings pageSettings, ExcelRangeBase cell) + { + if (!ExcelErrorValue.IsErrorValue(cell.Text)) return null; + switch (pageSettings.CellErrors) + { + case CellErrors.Blank: return ""; + case CellErrors.Dashed: return "--"; + case CellErrors.NA: return "#N/A"; + case CellErrors.Displayed: + default: return null; + } + } + + private static int MapUnderlineType(ExcelUnderLineType type) + { + // 12 = none, 13 = single, 4 = double (matches existing rendering code; accounting not supported). + if (type == ExcelUnderLineType.Single) return 13; + if (type == ExcelUnderLineType.Double) return 4; + return 12; + } + + private static FontSubFamily ComputeFontStyle(TextFragment textFrag) + { + if (textFrag.RichTextOptions.Bold && textFrag.RichTextOptions.Italic) return FontSubFamily.BoldItalic; + if(textFrag.RichTextOptions.Bold) return FontSubFamily.Bold; + if (textFrag.RichTextOptions.Italic) return FontSubFamily.Italic; + return FontSubFamily.Regular; + } + + internal static PdfCellAlignmentData GetAlignmentData(PdfHeaderFooter headerFooter) + { + var contentAlignment = new PdfCellAlignmentData(); + switch (headerFooter.Alignment) + { + case HeaderFooterAlignment.Left: + contentAlignment.HorizontalAlignment = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left; + break; + case HeaderFooterAlignment.Center: + contentAlignment.HorizontalAlignment = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center; + break; + case HeaderFooterAlignment.Right: + contentAlignment.HorizontalAlignment = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right; + break; + } + return contentAlignment; + } + + internal static PdfHeaderFooter GetTextFormats(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelWorksheet ws, ExcelHeaderFooterTextCollection textCollection, HeaderFooterType type, HeaderFooterAlignment alignment, HeaderFooterSection section) + { + if (textCollection == null || textCollection.Count <= 1) return null; + var ns = ws.Workbook.Styles.GetNormalStyle(); + var textFragments = new List(); + List NumberOfPagesIndexes = new List(); + List PageNumberIndexes = new List(); + for (int i = 1; i < textCollection.Count; i++) + { + var hf = textCollection[i]; + var textFrag = new TextFragment(); + textFrag.Font = new RichTextFormatSimple(); + textFrag.Font.Family = string.IsNullOrEmpty(hf.FontName) ? ns.Style.Font.Name : hf.FontName; + textFrag.Font.Size = hf.FontSize == null ? ns.Style.Font.Size : (float)hf.FontSize; + textFrag.RichTextOptions.Bold = hf.Bold; + textFrag.RichTextOptions.Italic = hf.Italic; + //underline + //none : 12 + //single : 13 + //Double : 4 + //accouting does not exsist + textFrag.RichTextOptions.UnderlineType = 12; + textFrag.RichTextOptions.UnderlineType = hf.Underline ? 13 : textFrag.RichTextOptions.UnderlineType; + textFrag.RichTextOptions.UnderlineType = hf.DoubleUnderline ? 4 : textFrag.RichTextOptions.UnderlineType; + textFrag.RichTextOptions.StrikeType = hf.Striketrough ? 2 : 1; + textFrag.RichTextOptions.FontColor = hf.Color; + textFrag.Font.SubFamily = ComputeFontStyle(textFrag); + var text = string.Empty; + switch (hf.FormatCode) + { + case ExcelHeaderFooterFormattingCodes.SheetName: + text += ws.Name; + break; + case ExcelHeaderFooterFormattingCodes.CurrentDate: + text += DateTime.Now.ToString($"yyyy-MM-dd"); + break; + case ExcelHeaderFooterFormattingCodes.FileName: + text += ws._package.File.Name; + break; + case ExcelHeaderFooterFormattingCodes.NumberOfPages: + text += "000"; + NumberOfPagesIndexes.Add(i-1); + break; + case ExcelHeaderFooterFormattingCodes.PageNumber: + text += "000"; + PageNumberIndexes.Add(i-1); + break; + case ExcelHeaderFooterFormattingCodes.CurrentTime: + text += DateTime.Now.ToString("HH:mm"); + break; + case ExcelHeaderFooterFormattingCodes.FilePath: + text += ws._package.File.Directory.FullName + "\\"; + break; + default: + text += hf.Text; + break; + } + textFrag.Text = text; + textFragments.Add(textFrag); + dictionaries.AddFont(pageSettings, textFrag.Font.Family, textFrag.Font.SubFamily, textFrag.Text); + if (NumberOfPagesIndexes.Count > 0 || PageNumberIndexes.Count > 0) dictionaries.AddFont(pageSettings, textFrag.Font.Family, textFrag.Font.SubFamily, "1234567890"); + } + return new PdfHeaderFooter(textFragments, PageNumberIndexes, NumberOfPagesIndexes, type, alignment, section); + } + + /// + /// Check if we need to add additional columns to accomodate text that is not wrapped and overlaps other cell.s + /// + /// The worksheet to check. + /// The number of columns to add. + internal static int AddColumnsForNonWrappedText(PdfPageSettings pageSettings, ExcelWorksheet ws, PdfWorksheet pdfSheet) + { + int columnsToAdd = 0; + var catalog = new PdfCatalog(); + var lastColumn = ws.Dimension.End.Column; + ExcelRangeBase lastColumnRange = ws.Cells[1, lastColumn, ws.Dimension.End.Row, lastColumn]; + var cc = catalog.GetCellCollectionFromRange(pageSettings, lastColumnRange); + double textLength = 0; + for (int i = cc.FromRow; i < cc.ToRow; i++) + { + textLength = cc[i, cc.FromColumn].TotalTextLength > textLength ? cc[i, cc.FromColumn].TotalTextLength : textLength; + } + double columnWidth = UnitConversion.ExcelColumnWidthToPoints(ws.Column(ws.Dimension._toCol).Width, pdfSheet.ZeroCharWidth); + while (textLength > columnWidth) + { + columnsToAdd++; + columnWidth += UnitConversion.ExcelColumnWidthToPoints(ws.Column(ws.Dimension._toCol + columnsToAdd).Width, pdfSheet.ZeroCharWidth); + } + return columnsToAdd; + } + + internal static ExcelDxfBorderItem GetTopBorderItem(ExcelRangeBase cell, ExcelBorderItem xfBorder, ExcelTable table, ExcelTableNamedStyle tableStyle) + { + var range = table.Range; + int tableRow = cell._fromRow - range._fromRow; + int tableCol = cell._fromCol - range._fromCol; + int ts = table.ShowHeader ? 1 : 0; + var top = tableRow == 0 ? tableStyle.WholeTable.Style.Border.Top : tableStyle.WholeTable.Style.Border.Horizontal; + if (table.ShowHeader && tableRow == 0) + { + if (tableStyle.HeaderRow.Style.Border.Top.HasValue) + { + top = tableStyle.HeaderRow.Style.Border.Top; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstHeaderCell.Style.Border.Top.HasValue) + { + top = tableStyle.FirstHeaderCell.Style.Border.Top; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastHeaderCell.Style.Border.Top.HasValue) + { + top = tableStyle.LastHeaderCell.Style.Border.Top; + } + } + else if (table.ShowTotal && cell._fromRow == range._toRow) + { + if (tableStyle.TotalRow.Style.Border.Top.HasValue) + { + top = tableStyle.TotalRow.Style.Border.Top; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstTotalCell.Style.Border.Top.HasValue) + { + top = tableStyle.FirstTotalCell.Style.Border.Top; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastTotalCell.Style.Border.Top.HasValue) + { + top = tableStyle.LastTotalCell.Style.Border.Top; + } + } + else + { + if (table.ShowColumnStripes &&/* tableStyle.FirstColumnStripe.Style.Border.Top.HasValue &&*/ (tableCol & 1) == 0) + { + if (cell._fromRow - ts > range._fromRow && cell._fromRow < range._toRow) + { + top = tableStyle.FirstColumnStripe.Style.Border.Horizontal; + } + else if (cell._fromRow <= range._toRow) + { + top = null; + } + else + { + top = tableStyle.FirstColumnStripe.Style.Border.Top; + } + } + if (table.ShowColumnStripes && /*tableStyle.SecondColumnStripe.Style.Border.Top.HasValue &&*/ (tableCol & 1) != 0) + { + if (cell._fromRow + ts > range._fromRow && cell._fromRow < range._toRow) + { + top = tableStyle.SecondColumnStripe.Style.Border.Horizontal; + } + else if (cell._fromRow <= range._toRow) + { + top = null; + } + else + { + top = tableStyle.SecondColumnStripe.Style.Border.Top; + } + } + if (table.ShowRowStripes && tableStyle.FirstRowStripe.Style.Border.Top.HasValue && (tableRow & 1) != 0) + { + top = tableStyle.FirstRowStripe.Style.Border.Top; + } + if (table.ShowRowStripes && tableStyle.SecondRowStripe.Style.Border.Top.HasValue && (tableRow & 1) == 0) + { + top = tableStyle.SecondRowStripe.Style.Border.Top; + } + if (table.ShowLastColumn && tableStyle.LastColumn.Style.Border.Top.HasValue && cell._fromCol == range._toCol) + { + top = tableStyle.LastColumn.Style.Border.Top; + } + if (table.ShowFirstColumn && tableStyle.FirstColumn.Style.Border.Top.HasValue && tableCol == range._toCol) + { + top = tableStyle.FirstColumn.Style.Border.Top; + } + } + return top; + } + internal static ExcelDxfBorderItem GetBottomBorderItem(ExcelRangeBase cell, ExcelBorderItem xfBorder, ExcelTable table, ExcelTableNamedStyle tableStyle) + { + var range = table.Range; + int tableRow = cell._fromRow - range._fromRow; + int tableCol = cell._fromCol - range._fromCol; + var bottom = range._toRow == cell._fromRow ? tableStyle.WholeTable.Style.Border.Bottom : null; + if (table.ShowHeader && tableRow == 0) + { + if (tableStyle.HeaderRow.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.HeaderRow.Style.Border.Bottom; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstHeaderCell.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.FirstHeaderCell.Style.Border.Bottom; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastHeaderCell.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.LastHeaderCell.Style.Border.Bottom; + } + } + else if (table.ShowTotal && cell._fromRow == range._toRow) + { + if (tableStyle.TotalRow.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.TotalRow.Style.Border.Bottom; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstTotalCell.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.FirstTotalCell.Style.Border.Bottom; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastTotalCell.Style.Border.Bottom.HasValue) + { + bottom = tableStyle.LastTotalCell.Style.Border.Bottom; + } + } + else + { + if (table.ShowColumnStripes && tableStyle.FirstColumnStripe.Style.Border.Bottom.HasValue && (tableCol & 1) != 0) + { + if (cell._fromRow > range._fromRow && cell._fromRow < range._toRow) + { + bottom = tableStyle.FirstColumnStripe.Style.Border.Horizontal; + } + else if (cell._fromRow < range._toRow) + { + bottom = null; + } + else + { + bottom = tableStyle.FirstColumnStripe.Style.Border.Bottom; + } + } + if (table.ShowColumnStripes && tableStyle.SecondColumnStripe.Style.Border.Bottom.HasValue && (tableCol & 1) == 0) + { + if (cell._fromRow > range._fromRow && cell._fromRow < range._toRow) + { + bottom = tableStyle.SecondColumnStripe.Style.Border.Horizontal; + } + else if (cell._fromRow < range._toRow) + { + bottom = null; + } + else + { + bottom = tableStyle.SecondColumnStripe.Style.Border.Bottom; + } + } + if (table.ShowRowStripes && tableStyle.FirstRowStripe.Style.Border.Bottom.HasValue && (tableRow & 1) != 0) + { + bottom = tableStyle.FirstRowStripe.Style.Border.Bottom; + } + if (table.ShowRowStripes && tableStyle.SecondRowStripe.Style.Border.Bottom.HasValue && (tableRow & 1) == 0) + { + bottom = tableStyle.SecondRowStripe.Style.Border.Bottom; + } + if (table.ShowLastColumn && tableStyle.LastColumn.Style.Border.Bottom.HasValue && cell._fromCol == range._toCol) + { + bottom = tableStyle.LastColumn.Style.Border.Bottom; + } + if (table.ShowFirstColumn && tableStyle.FirstColumn.Style.Border.Bottom.HasValue && tableCol == 0) + { + bottom = tableStyle.FirstColumn.Style.Border.Bottom; + } + } + return bottom; + } + internal static ExcelDxfBorderItem GetLeftBorderItem(ExcelRangeBase cell, ExcelBorderItem xfBorder, ExcelTable table, ExcelTableNamedStyle tableStyle) + { + var range = table.Range; + int tableRow = cell._fromRow - range._fromRow; + int tableCol = cell._fromCol - range._fromCol; + var left = tableCol == 0 ? tableStyle.WholeTable.Style.Border.Left : tableStyle.WholeTable.Style.Border.Vertical; + if (table.ShowHeader && tableRow == 0) + { + if (tableStyle.HeaderRow.Style.Border.Left.HasValue) + { + left = tableStyle.HeaderRow.Style.Border.Left; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstHeaderCell.Style.Border.Left.HasValue) + { + left = tableStyle.FirstHeaderCell.Style.Border.Left; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastHeaderCell.Style.Border.Left.HasValue) + { + left = tableStyle.LastHeaderCell.Style.Border.Left; + } + } + else if (table.ShowTotal && cell._fromRow == range._toRow) + { + if (tableStyle.TotalRow.Style.Border.Left.HasValue) + { + left = tableStyle.TotalRow.Style.Border.Left; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstTotalCell.Style.Border.Left.HasValue) + { + left = tableStyle.FirstTotalCell.Style.Border.Left; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastTotalCell.Style.Border.Left.HasValue) + { + left = tableStyle.LastTotalCell.Style.Border.Left; + } + } + else + { + if (table.ShowColumnStripes && tableStyle.FirstColumnStripe.Style.Border.Left.HasValue && (tableCol & 1) != 0) + { + left = tableStyle.FirstColumnStripe.Style.Border.Left; + } + if (table.ShowColumnStripes && tableStyle.SecondColumnStripe.Style.Border.Left.HasValue && (tableCol & 1) == 0) + { + left = tableStyle.SecondColumnStripe.Style.Border.Left; + } + if (table.ShowRowStripes && tableStyle.FirstRowStripe.Style.Border.Left.HasValue && (tableRow & 1) != 0) + { + if (cell._fromCol > range._fromCol && cell._fromCol < range._toCol) + { + left = tableStyle.FirstRowStripe.Style.Border.Vertical; + } + else if (cell._fromCol >= range._toCol) + { + left = null; + } + else + { + left = tableStyle.FirstRowStripe.Style.Border.Left; + } + } + if (table.ShowRowStripes && tableStyle.SecondRowStripe.Style.Border.Left.HasValue && (tableRow & 1) == 0) + { + if (cell._fromCol > range._fromCol && cell._fromCol < range._toCol) + { + left = tableStyle.SecondRowStripe.Style.Border.Vertical; + } + else if (cell._fromCol >= range._toCol) + { + left = null; + } + else + { + left = tableStyle.SecondRowStripe.Style.Border.Left; + } + } + if (table.ShowLastColumn && tableStyle.LastColumn.Style.Border.Left.HasValue && cell._fromCol == range._toCol) + { + left = tableStyle.LastColumn.Style.Border.Left; + } + if (table.ShowFirstColumn && tableStyle.FirstColumn.Style.Border.Left.HasValue && tableCol == range._toCol) + { + left = tableStyle.FirstColumn.Style.Border.Left; + } + } + return left; + } + internal static ExcelDxfBorderItem GetRightBorderItem(ExcelRangeBase cell, ExcelBorderItem xfBorder, ExcelTable table, ExcelTableNamedStyle tableStyle) + { + var range = table.Range; + int tableRow = cell._fromRow - range._fromRow; + int tableCol = cell._fromCol - range._fromCol; + var right = cell._fromCol == range._toCol ? tableStyle.WholeTable.Style.Border.Right : tableStyle.WholeTable.Style.Border.Vertical; + if (table.ShowHeader && tableRow == 0) + { + if (tableStyle.HeaderRow.Style.Border.Right.HasValue) + { + right = tableStyle.HeaderRow.Style.Border.Right; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstHeaderCell.Style.Border.Right.HasValue) + { + right = tableStyle.FirstHeaderCell.Style.Border.Right; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastHeaderCell.Style.Border.Right.HasValue) + { + right = tableStyle.LastHeaderCell.Style.Border.Right; + } + } + else if (table.ShowTotal && cell._fromRow == range._toRow) + { + if (tableStyle.TotalRow.Style.Border.Right.HasValue) + { + right = tableStyle.TotalRow.Style.Border.Right; + } + if (tableCol == 0 && table.ShowFirstColumn && tableStyle.FirstTotalCell.Style.Border.Right.HasValue) + { + right = tableStyle.FirstTotalCell.Style.Border.Right; + } + if (cell._fromCol == range._toCol && table.ShowLastColumn && tableStyle.LastTotalCell.Style.Border.Right.HasValue) + { + right = tableStyle.LastTotalCell.Style.Border.Right; + } + } + else + { + if (table.ShowColumnStripes && tableStyle.FirstColumnStripe.Style.Border.Right.HasValue && (tableCol & 1) != 0) + { + right = tableStyle.FirstColumnStripe.Style.Border.Right; + } + if (table.ShowColumnStripes && tableStyle.SecondColumnStripe.Style.Border.Right.HasValue && (tableCol & 1) == 0) + { + right = tableStyle.SecondColumnStripe.Style.Border.Right; + } + if (table.ShowRowStripes && tableStyle.FirstRowStripe.Style.Border.Right.HasValue && (tableRow & 1) != 0) + { + if (cell._fromCol > range._fromCol && cell._fromCol < range._toCol) + { + right = tableStyle.FirstRowStripe.Style.Border.Vertical; + } + else if (cell._fromCol < range._toCol) + { + right = null; + } + else + { + right = tableStyle.FirstRowStripe.Style.Border.Right; + } + } + if (table.ShowRowStripes && tableStyle.SecondRowStripe.Style.Border.Right.HasValue && (tableRow & 1) == 0) + { + if (cell._fromCol > range._fromCol && cell._fromCol < range._toCol) + { + right = tableStyle.SecondRowStripe.Style.Border.Vertical; + } + else if (cell._fromCol < range._toCol) + { + right = null; + } + else + { + right = tableStyle.SecondRowStripe.Style.Border.Right; + } + } + if (table.ShowLastColumn && tableStyle.LastColumn.Style.Border.Right.HasValue && cell._fromCol == range._toCol) + { + right = tableStyle.LastColumn.Style.Border.Right; + } + if (table.ShowFirstColumn && tableStyle.FirstColumn.Style.Border.Right.HasValue && tableCol == range._toCol) + { + right = tableStyle.FirstColumn.Style.Border.Right; + } + } + return right; + } + } +} diff --git a/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs b/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs new file mode 100644 index 0000000000..f179868d6f --- /dev/null +++ b/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs @@ -0,0 +1,176 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Fonts.OpenType; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.TextShaping; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Layout; +using OfficeOpenXml.Export.PdfExport.Data; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OfficeOpenXml.Export.PdfExport.TextShaping +{ + internal static class PdfTextShaper + { + private static Dictionary shaperCache = new Dictionary(); + private static Dictionary layoutEngineCache = new Dictionary(); + + // Pass 1: collect text per font so FontSubsetManager can build subsets once + public static void CollectText(PdfDictionaries dictionaries, PdfCell cell) + { + if (cell == null || cell.TextFragments == null) return; + for (int i = 0; i < cell.TextFragments.Count; i++) + { + var tf = cell.TextFragments[i]; + if (!dictionaries.Fonts.ContainsKey(tf.FullFontName)) continue; + dictionaries.Fonts[tf.FullFontName].fontSubsetManager.AddText(tf.Text); + } + } + + // Pass 2: shape text using already-built providers from PdfDictionaries.ShapedProviders + public static void ShapeText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfCell cell) + { + var totalTextLength = 0d; + var maxLineHeight = 0d; + if (cell == null || cell.TextFragments == null) return; + cell.ShapedTexts = new List(); + for (int i = 0; i < cell.TextFragments.Count; i++) + { + var tf = cell.TextFragments[i]; + cell.ShapedTexts.Add(new PdfShapedText()); + var st = cell.ShapedTexts[i]; + if (!dictionaries.ShapedProviders.TryGetValue(tf.FullFontName, out var provider)) + { + continue; + } + st.FontProvider = provider; + if (!shaperCache.TryGetValue(st.FontProvider, out var shaper)) + { + shaper = new TextShaper(st.FontProvider); + shaperCache[st.FontProvider] = shaper; + } + if (!layoutEngineCache.TryGetValue(st.FontProvider, out var layoutEngine)) + { + layoutEngine = new TextLayoutEngine(shaper); + layoutEngineCache[st.FontProvider] = layoutEngine; + } + var options = ShapingOptions.Default; + options.ApplyPositioning = true; + options.ApplySubstitutions = true; + var shaped = shaper.Shape(tf.Text, options); + var usedFonts = shaper.GetUsedFonts().ToList(); + var fontIdMap = new Dictionary(); + for (byte fontId = 0; fontId < usedFonts.Count; fontId++) + { + var font = usedFonts[fontId]; + if (!dictionaries.Fonts.ContainsKey(font.FullName)) + { + int label = dictionaries.Fonts.Count > 0 + ? dictionaries.Fonts.Last().Value.labelNumber + 1 + : 1; + var fontResource = new PdfFontResource(font.FullName, font.NameTable.GetSubfamilyEnum(), label, pageSettings); + fontResource.fontData = font; + dictionaries.Fonts.Add(font.FullName, fontResource); + } + fontIdMap[fontId] = dictionaries.Fonts[font.FullName].Label; + } + cell.TextLayoutEngine = layoutEngine; + st.ShapedText = shaped; + totalTextLength += st.ShapedText.GetWidthInPoints((float)tf.Font.Size); + maxLineHeight = Math.Max(st.ShapedText.GetLineHeightInPoints((float)tf.Font.Size), maxLineHeight); + st.FontIdMap = fontIdMap; + st.UsedFonts = usedFonts; + cell.TextFragments[i] = tf; + cell.ShapedTexts[i] = st; + } + if (cell.TextLayoutEngine != null) + { + double wrapWidth = (cell.Merged && cell.Main == null) ? cell.Width : cell.ColumnWidth; + cell.TextLines = cell.ContentAligmnet.WrapText + ? cell.TextLayoutEngine.WrapRichTextLineCollection(cell.TextFragments, wrapWidth) + : cell.TextLayoutEngine.WrapRichTextLineCollection(cell.TextFragments, double.MaxValue); + } + cell.TotalTextLength = totalTextLength; + } + + // Pass 2: shape text using already-built providers from PdfDictionaries.ShapedProviders + public static void ShapeText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfCellBase cell) + { + var totalTextLength = 0d; + var maxLineHeight = 0d; + if (cell == null || cell.TextFragments == null) return; + cell.ShapedTexts = new List(); + for (int i = 0; i < cell.TextFragments.Count; i++) + { + var tf = cell.TextFragments[i]; + cell.ShapedTexts.Add(new PdfShapedText()); + var st = cell.ShapedTexts[i]; + if (!dictionaries.ShapedProviders.TryGetValue(tf.FullFontName, out var provider)) + { + continue; + } + st.FontProvider = provider; + if (!shaperCache.TryGetValue(st.FontProvider, out var shaper)) + { + shaper = new TextShaper(st.FontProvider); + shaperCache[st.FontProvider] = shaper; + } + if (!layoutEngineCache.TryGetValue(st.FontProvider, out var layoutEngine)) + { + layoutEngine = new TextLayoutEngine(shaper); + layoutEngineCache[st.FontProvider] = layoutEngine; + } + var options = ShapingOptions.Default; + options.ApplyPositioning = true; + options.ApplySubstitutions = true; + var shaped = shaper.Shape(tf.Text, options); + var usedFonts = shaper.GetUsedFonts().ToList(); + var fontIdMap = new Dictionary(); + for (byte fontId = 0; fontId < usedFonts.Count; fontId++) + { + var font = usedFonts[fontId]; + if (!dictionaries.Fonts.ContainsKey(font.FullName)) + { + int label = dictionaries.Fonts.Count > 0 + ? dictionaries.Fonts.Last().Value.labelNumber + 1 + : 1; + var fontResource = new PdfFontResource(font.FullName, font.NameTable.GetSubfamilyEnum(), label, pageSettings); + fontResource.fontData = font; + dictionaries.Fonts.Add(font.FullName, fontResource); + } + fontIdMap[fontId] = dictionaries.Fonts[font.FullName].Label; + } + cell.TextLayoutEngine = layoutEngine; + st.ShapedText = shaped; + totalTextLength += st.ShapedText.GetWidthInPoints((float)tf.Font.Size); + maxLineHeight = Math.Max(st.ShapedText.GetLineHeightInPoints((float)tf.Font.Size), maxLineHeight); + st.FontIdMap = fontIdMap; + st.UsedFonts = usedFonts; + cell.TextFragments[i] = tf; + cell.ShapedTexts[i] = st; + } + if (cell.TextLayoutEngine != null) + { + double wrapWidth = cell.Width; + cell.TextLines = cell.ContentAligmnet.WrapText + ? cell.TextLayoutEngine.WrapRichTextLineCollection(cell.TextFragments, wrapWidth) + : cell.TextLayoutEngine.WrapRichTextLineCollection(cell.TextFragments, double.MaxValue); + } + cell.TotalTextLength = totalTextLength; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Export/ToDataTable/DataColumnMapping.cs b/src/EPPlus/Export/ToDataTable/DataColumnMapping.cs index e55ff43045..649831fb03 100644 --- a/src/EPPlus/Export/ToDataTable/DataColumnMapping.cs +++ b/src/EPPlus/Export/ToDataTable/DataColumnMapping.cs @@ -75,7 +75,7 @@ public string DataColumnName private Type _dataColumnType; /// - /// Type of the column, corresponds to + /// BulletType of the column, corresponds to /// public Type ColumnDataType { diff --git a/src/EPPlus/Export/ToDataTable/ToDataTableOptions.cs b/src/EPPlus/Export/ToDataTable/ToDataTableOptions.cs index 3cd7480ef5..c4185c14f7 100644 --- a/src/EPPlus/Export/ToDataTable/ToDataTableOptions.cs +++ b/src/EPPlus/Export/ToDataTable/ToDataTableOptions.cs @@ -163,9 +163,9 @@ public void SetPrimaryKey(params string[] columnNames) } /// - /// Sets the primary key of the data table. + /// Sets the primary _key of the data table. /// - /// The index or indexes of one or more column in the range that builds up the primary key of the + /// The index or indexes of one or more column in the range that builds up the primary _key of the public void SetPrimaryKey(params int[] zeroBasedRangeIndexes) { _primaryKeyIndexes.Clear(); diff --git a/src/EPPlus/ExternalReferences/ExcelExternalLinksCollection.cs b/src/EPPlus/ExternalReferences/ExcelExternalLinksCollection.cs index 7bd53fa630..301908e1b5 100644 --- a/src/EPPlus/ExternalReferences/ExcelExternalLinksCollection.cs +++ b/src/EPPlus/ExternalReferences/ExcelExternalLinksCollection.cs @@ -76,15 +76,16 @@ public ExcelExternalLink this[int index] /// Adds an external reference to another workbook. /// /// The location of the external workbook. The external workbook must of type .xlsx, .xlsm or xlst + /// Add the workbooks path as absolute if possible. /// The object - public ExcelExternalWorkbook AddExternalWorkbook(FileInfo file) + public ExcelExternalWorkbook AddExternalWorkbook(FileInfo file, bool absolute=false) { if(file == null || file.Exists==false) { throw (new FileNotFoundException("The file does not exist.")); } var p = new ExcelPackage(file); - var ewb = new ExcelExternalWorkbook(_wb, p); + var ewb = new ExcelExternalWorkbook(_wb, p, absolute); _list.Add(ewb); return ewb; } diff --git a/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs b/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs index ae023695ea..a6d45e4aa9 100644 --- a/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs +++ b/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs @@ -37,11 +37,12 @@ public class ExcelExternalWorkbook : ExcelExternalLink Dictionary> _sheetMetaData = new Dictionary>(); Dictionary> _definedNamesValues = new Dictionary>(); HashSet _sheetRefresh = new HashSet(); - internal ExcelExternalWorkbook(ExcelWorkbook wb, ExcelPackage p) : base(wb) + internal ExcelExternalWorkbook(ExcelWorkbook wb, ExcelPackage p, bool absolute) : base(wb) { CachedWorksheets = new ExcelExternalNamedItemCollection(); CachedNames = new ExcelExternalNamedItemCollection(); CacheStatus = eExternalWorkbookCacheStatus.NotUpdated; + IsPathRelative = !absolute; SetPackage(p, false); } internal ExcelExternalWorkbook(ExcelWorkbook wb, XmlTextReader reader, ZipPackagePart part, XmlElement workbookElement) : base(wb, reader, part, workbookElement) diff --git a/src/EPPlus/Filter/ExcelDynamicFilterColumn.cs b/src/EPPlus/Filter/ExcelDynamicFilterColumn.cs index b80dab416a..6f69c68fe1 100644 --- a/src/EPPlus/Filter/ExcelDynamicFilterColumn.cs +++ b/src/EPPlus/Filter/ExcelDynamicFilterColumn.cs @@ -19,7 +19,7 @@ Date Author Change namespace OfficeOpenXml.Filter { /// - /// Various filters that are set depending on the filter Type + /// Various filters that are set depending on the filter BulletType /// /// public class ExcelDynamicFilterColumn : ExcelFilterColumn @@ -30,7 +30,7 @@ internal ExcelDynamicFilterColumn(XmlNamespaceManager namespaceManager, XmlNode } /// - /// Type of filter + /// BulletType of filter /// public eDynamicFilterType Type { get; set; } /// diff --git a/src/EPPlus/Filter/ExcelValueFilterColumn.cs b/src/EPPlus/Filter/ExcelValueFilterColumn.cs index aa64648cf7..175b0db53e 100644 --- a/src/EPPlus/Filter/ExcelValueFilterColumn.cs +++ b/src/EPPlus/Filter/ExcelValueFilterColumn.cs @@ -29,7 +29,7 @@ internal ExcelValueFilterColumn(XmlNamespaceManager namespaceManager, XmlNode to private void LoadFilters(XmlNode topNode) { - foreach (XmlNode node in topNode.FirstChild.ChildNodes) + foreach (XmlElement node in topNode.FirstChild.ChildNodes) { switch (node.LocalName) { diff --git a/src/EPPlus/FormulaParsing/Excel/Functions/Finance/Implementations/IPmtImpl.cs b/src/EPPlus/FormulaParsing/Excel/Functions/Finance/Implementations/IPmtImpl.cs index 9879b5dc10..1567a1724f 100644 --- a/src/EPPlus/FormulaParsing/Excel/Functions/Finance/Implementations/IPmtImpl.cs +++ b/src/EPPlus/FormulaParsing/Excel/Functions/Finance/Implementations/IPmtImpl.cs @@ -33,7 +33,7 @@ internal static FinanceCalcResult Ipmt(double Rate, double Per, double N dTemp = 1; } - // Type = 0 or non-zero only. Offset to calculate FV + // BulletType = 0 or non-zero only. Offset to calculate FV if((Per <= 0) || (Per >= NPer + 1)) { return new FinanceCalcResult(eErrorType.Value); diff --git a/src/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs b/src/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs index f0e3b69d5a..698eb616c7 100644 --- a/src/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs +++ b/src/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs @@ -35,6 +35,6 @@ public interface IFunctionModule ///// is created, it should be given a reference to the same function instance that exists ///// in the Functions collection of this module. ///// - //IDictionary CustomCompilers { get; } + //IDictionary CustomCompilers { get; } } } diff --git a/src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupUtils/XlookupScanner.cs b/src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupUtils/XlookupScanner.cs index c244811db3..6dcc60ceff 100644 --- a/src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupUtils/XlookupScanner.cs +++ b/src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupUtils/XlookupScanner.cs @@ -91,7 +91,7 @@ private int FindIndexInternal() else { //dimensionItems = _lookupRange.Dimension.ToCol - _lookupRange.Dimension.FromCol + 1; - //maxItems = _lookupRange.Size.NumberOfCols > dimensionItems ? dimensionItems : _lookupRange.Size.NumberOfCols; + //maxItems = _lookupRange.FontSize.NumberOfCols > dimensionItems ? dimensionItems : _lookupRange.FontSize.NumberOfCols; maxItems = GetMaxItemsColumns(_lookupRange); } int closestBelowIx = -1; diff --git a/src/EPPlus/FormulaParsing/FormulaParserManager.cs b/src/EPPlus/FormulaParsing/FormulaParserManager.cs index 980da6044a..0b48a6fead 100644 --- a/src/EPPlus/FormulaParsing/FormulaParserManager.cs +++ b/src/EPPlus/FormulaParsing/FormulaParserManager.cs @@ -87,7 +87,7 @@ public IEnumerable GetImplementedFunctionNames() /// /// Returns an enumeration of all implemented functions, including the implementing instance. /// - /// An enumeration of , where the key is the function name + /// An enumeration of , where the _key is the function name public IEnumerable> GetImplementedFunctions() { var functions = new List>(); diff --git a/src/EPPlus/FormulaParsing/IRangeInfo.cs b/src/EPPlus/FormulaParsing/IRangeInfo.cs index 1cfa958101..e121136a2b 100644 --- a/src/EPPlus/FormulaParsing/IRangeInfo.cs +++ b/src/EPPlus/FormulaParsing/IRangeInfo.cs @@ -49,7 +49,7 @@ public interface IRangeInfo : IAddressInfo, IEnumerator, IEnumerable< int GetNCells(); /// - /// Size of the range, i.e. number of Cols and number of Rows + /// FontSize of the range, i.e. number of Cols and number of Rows /// RangeDefinition Size { get; } /// diff --git a/src/EPPlus/FormulaParsing/Ranges/EpplusExcelExternalRangeInfo.cs b/src/EPPlus/FormulaParsing/Ranges/EpplusExcelExternalRangeInfo.cs index ac3549eb2e..93ce12f1f2 100644 --- a/src/EPPlus/FormulaParsing/Ranges/EpplusExcelExternalRangeInfo.cs +++ b/src/EPPlus/FormulaParsing/Ranges/EpplusExcelExternalRangeInfo.cs @@ -184,7 +184,7 @@ public bool IsMulti } /// - /// Size of the range + /// FontSize of the range /// public RangeDefinition Size => _size; diff --git a/src/EPPlus/FormulaParsing/Ranges/RangeInfo.cs b/src/EPPlus/FormulaParsing/Ranges/RangeInfo.cs index b98f1c2a44..ef377bf785 100644 --- a/src/EPPlus/FormulaParsing/Ranges/RangeInfo.cs +++ b/src/EPPlus/FormulaParsing/Ranges/RangeInfo.cs @@ -211,7 +211,7 @@ public bool IsMulti } /// - /// Size of the range + /// FontSize of the range /// public RangeDefinition Size => _size; diff --git a/src/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs b/src/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs index 7246207ddf..eb1d081ab2 100644 --- a/src/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs +++ b/src/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs @@ -20,7 +20,7 @@ namespace OfficeOpenXml.FormulaParsing.Utilities /// /// Represent a function argument to validate /// - /// Type of the argument to validate + /// BulletType of the argument to validate public class ArgumentInfo { /// diff --git a/src/EPPlus/NumberFormatToTextArgs.cs b/src/EPPlus/NumberFormatToTextArgs.cs index 1bbfbe8b66..88b87ec256 100644 --- a/src/EPPlus/NumberFormatToTextArgs.cs +++ b/src/EPPlus/NumberFormatToTextArgs.cs @@ -77,7 +77,7 @@ internal NumberFormatToTextArgs(ExcelWorksheet ws, int row, int column, object v public IExcelNumberFormat NumberFormat { get - { + { if(fallbackNumberFormat != null) { return fallbackNumberFormat; diff --git a/src/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs b/src/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs index 1247432129..a5d1af7be4 100644 --- a/src/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs +++ b/src/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs @@ -74,7 +74,7 @@ namespace OfficeOpenXml.Packaging.Ionic.Zip /// /// In case you care: According to the WinZip specification, the - /// actual AES key used is derived from the via an + /// actual AES _key used is derived from the via an /// algorithm that complies with RFC 2898, using an iteration /// count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands diff --git a/src/EPPlus/Packaging/DotNetZip/FileSelector.cs b/src/EPPlus/Packaging/DotNetZip/FileSelector.cs index f6103d8fe3..fd5d38d239 100644 --- a/src/EPPlus/Packaging/DotNetZip/FileSelector.cs +++ b/src/EPPlus/Packaging/DotNetZip/FileSelector.cs @@ -1413,7 +1413,7 @@ internal static string GetDescription(System.Enum value) /// or more enumerated constants to an equivalent enumerated object. /// Note: use the DescriptionAttribute on enum values to enable this. /// - /// The System.Type of the enumeration. + /// The System.BulletType of the enumeration. /// /// A string containing the name or value to convert. /// @@ -1457,7 +1457,7 @@ select field.Name /// parameter specified whether the operation is case-sensitive. Note: /// use the DescriptionAttribute on enum values to enable this. /// - /// The System.Type of the enumeration. + /// The System.BulletType of the enumeration. /// /// A string containing the name or value to convert. /// diff --git a/src/EPPlus/Packaging/DotNetZip/ZipCrypto.cs b/src/EPPlus/Packaging/DotNetZip/ZipCrypto.cs index 6e7f62561d..97cf67a80e 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipCrypto.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipCrypto.cs @@ -269,10 +269,10 @@ public byte[] EncryptMessage(byte[] plainText, int length) /// Where update_keys() is defined as: /// /// update_keys(char): - /// Key(0) := crc32(key(0),char) + /// Key(0) := crc32(_key(0),char) /// Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH) /// Key(1) := Key(1) * 134775813 + 1 - /// Key(2) := crc32(key(2),key(1) rightshift 24) + /// Key(2) := crc32(_key(2),_key(1) rightshift 24) /// end update_keys /// /// Where crc32(old_crc,char) is a routine that given a CRC value and a diff --git a/src/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs b/src/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs index c5d176dc78..23650917bb 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs @@ -202,7 +202,7 @@ private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding if (ze._InputUsesZip64) { - // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size) + // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed FontSize, Uncompressed FontSize) block = new byte[20]; n = ze.ArchiveStream.Read(block, 0, block.Length); if (n != 20) return false; @@ -220,7 +220,7 @@ private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding } else { - // read 3x 4-byte fields (CRC, Compressed Size, Uncompressed Size) + // read 3x 4-byte fields (CRC, Compressed FontSize, Uncompressed FontSize) block = new byte[12]; n = ze.ArchiveStream.Read(block, 0, block.Length); if (n != 12) return false; @@ -316,7 +316,7 @@ internal static int ReadWeakEncryptionHeader(Stream s, byte[] buffer) // Each PKZIP-encrypted file has an extra 12 bytes stored at the start of the data // area defining the encryption header for that file. The encryption header is // originally set to random values, and then itself encrypted, using three, 32-bit - // keys. The key values are initialized using the supplied encryption password. + // keys. The _key values are initialized using the supplied encryption password. // After each byte is encrypted, the keys are then updated using pseudo-random // number generation techniques in combination with the same CRC-32 algorithm used // in PKZIP and implemented in the CRC32.cs module in this project. @@ -550,13 +550,13 @@ internal int ProcessExtraField(Stream s, Int16 extraFieldLength) private int ProcessExtraFieldPkwareStrongEncryption(byte[] Buffer, int j) { - // Value Size Description + // Value FontSize Description // ----- ---- ----------- // 0x0017 2 bytes Tag for this "extra" block type - // TSize 2 bytes Size of data that follows + // TSize 2 bytes FontSize of data that follows // Format 2 bytes Format definition for this record // AlgID 2 bytes Encryption algorithm identifier - // Bitlen 2 bytes Bit length of encryption key + // Bitlen 2 bytes Bit length of encryption _key // Flags 2 bytes Processing flags // CertData TSize-8 Certificate decryption extra field data // (refer to the explanation for CertData diff --git a/src/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs b/src/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs index d87bcc151b..da25bd6945 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs @@ -977,7 +977,7 @@ internal void WriteHeader(Stream s, int cycle) block[i++] = (byte)(_BitField & 0x00FF); block[i++] = (byte)((_BitField & 0xFF00) >> 8); - // Here, we want to set values for Compressed Size, Uncompressed Size, + // Here, we want to set values for Compressed FontSize, Uncompressed FontSize, // and CRC. If we have __FileDataPosition as not -1 (zero is a valid // FDP), then that means we are reading this zip entry from a zip // file, and we have good values for those quantities. @@ -1932,7 +1932,7 @@ private Stream MaybeApplyCompression(Stream s, long streamLength) // It's expensive to create a ParallelDeflateOutputStream, because // of the large memory buffers. But the class is unlike most Stream // classes in that it can be re-used, so the caller can compress - // multiple files with it, one file at a time. The key is to call + // multiple files with it, one file at a time. The _key is to call // Reset() on it, in between uses. // // The ParallelDeflateOutputStream is attached to the container diff --git a/src/EPPlus/Packaging/DotNetZip/ZipEntry.cs b/src/EPPlus/Packaging/DotNetZip/ZipEntry.cs index 22a5ec340b..8f0bdfb733 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipEntry.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipEntry.cs @@ -273,7 +273,7 @@ private int BufferSize /// times of a particular file. These metadata are not actually specific /// to NTFS or Unix. They are tracked for each file by NTFS and by various /// Unix filesystems, but they are also tracked by other filesystems, too. - /// The key point is that the times are formatted in the zip file + /// The _key point is that the times are formatted in the zip file /// in the same way that NTFS formats the time (ticks since win32 epoch), /// or in the same way that Unix formats the time (seconds since Unix /// epoch). As with the DOS time, any tool or library running on any @@ -1049,7 +1049,7 @@ internal ZipEntrySource Source /// /// /// 61 - /// File is encrypted using non-OAEP key wrapping*** + /// File is encrypted using non-OAEP _key wrapping*** /// /// /// @@ -1644,7 +1644,7 @@ public bool UsesEncryption /// by PKWare, but this encryption is considered weak and /// breakable. This library currently supports the Zip 2.0 "weak" encryption, /// and also a stronger WinZip-compatible AES encryption, using either 128-bit - /// or 256-bit key strength. If you want DotNetZip to support an algorithm + /// or 256-bit _key strength. If you want DotNetZip to support an algorithm /// that is not currently supported, call the author of this library and maybe /// we can talk business. /// diff --git a/src/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs b/src/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs index 8bc73393b7..ddd1f01aa8 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs @@ -1461,7 +1461,7 @@ public ZipEntry AddEntry(string entryName, Stream stream) /// This example uses a named delegate in VB to write data for the given /// ZipEntry (VB9 does not have anonymous delegates). The example here is a bit /// contrived - a simpler way to add the contents of a file to a ZipEntry is to - /// simply use the appropriate AddFile() method. The key scenario for + /// simply use the appropriate AddFile() method. The _key scenario for /// which the WriteDelegate makes sense is saving a DataSet, in XML /// format, to the zip file. The DataSet can write XML to a stream, and the /// WriteDelegate is the perfect place to write into the zip file. There may be @@ -1628,7 +1628,7 @@ private ZipEntry _InternalAddEntry(ZipEntry ze) ze.Encryption = this.Encryption; ze.EmitTimesInWindowsFormatWhenSaving = this._emitNtfsTimes; ze.EmitTimesInUnixFormatWhenSaving = this._emitUnixTimes; - //string key = DictionaryKeyForEntry(ze); + //string _key = DictionaryKeyForEntry(ze); InternalAddEntry(ze.FileName,ze); AfterAddEntry(ze); return ze; @@ -2059,7 +2059,7 @@ public ZipEntry AddDirectoryByName(string directoryNameInArchive) dir.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes; dir.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes; dir._Source = ZipEntrySource.Stream; - //string key = DictionaryKeyForEntry(dir); + //string _key = DictionaryKeyForEntry(dir); InternalAddEntry(dir.FileName,dir); AfterAddEntry(dir); return dir; diff --git a/src/EPPlus/Packaging/DotNetZip/ZipFile.cs b/src/EPPlus/Packaging/DotNetZip/ZipFile.cs index 621ff5f7c8..f99f558953 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipFile.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipFile.cs @@ -260,7 +260,7 @@ public bool SortEntriesBeforeSaving /// - /// Size of the IO buffer used while saving. + /// FontSize of the IO buffer used while saving. /// /// /// @@ -323,7 +323,7 @@ public int BufferSize } /// - /// Size of the work buffer to use for the ZLIB codec during compression. + /// FontSize of the work buffer to use for the ZLIB codec during compression. /// /// /// @@ -2649,7 +2649,7 @@ public ZipFile(System.Text.Encoding encoding) /// System.Console.Out to get messages on the Console. A graphical or headless /// application may wish to capture the messages in a different /// TextWriter, for example, a StringWriter, and then display - /// the messages in a TextBox, or generate an audit log of ZipFile operations. + /// the messages in a RenderTextbox, or generate an audit log of ZipFile operations. /// /// /// @@ -2731,7 +2731,7 @@ public ZipFile(string fileName, TextWriter statusMessageWriter) /// System.Console.Out to get messages on the Console. A graphical or /// headless application may wish to capture the messages in a different /// TextWriter, for example, a StringWriter, and then display - /// the messages in a TextBox, or generate an audit log of + /// the messages in a RenderTextbox, or generate an audit log of /// ZipFile operations. /// /// diff --git a/src/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs b/src/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs index bb607b1d66..ab9bd029b0 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs @@ -72,7 +72,7 @@ internal partial class ZipFile /// System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField); /// System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod); /// System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}", - /// "Filename", "Modified", "Size", "Ratio", "Packed"); + /// "Filename", "Modified", "FontSize", "Ratio", "Packed"); /// System.Console.WriteLine(new System.String('-', 72)); /// header = false; /// } @@ -101,7 +101,7 @@ internal partial class ZipFile /// Console.WriteLine("BitField: 0x{0:X2}", e.BitField) /// Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod) /// Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _ - /// "Filename", "Modified", "Size", "Ratio", "Packed" ) + /// "Filename", "Modified", "FontSize", "Ratio", "Packed" ) /// Console.WriteLine(New String("-"c, 72)) /// header = False /// End If diff --git a/src/EPPlus/Packaging/DotNetZip/ZipInputStream.cs b/src/EPPlus/Packaging/DotNetZip/ZipInputStream.cs index 585dd084e2..6fe6803627 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipInputStream.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipInputStream.cs @@ -364,7 +364,7 @@ public override String ToString() return String.Format ("ZipInputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen); } /// - /// Size of the work buffer to use for the ZLIB codec during decompression. + /// FontSize of the work buffer to use for the ZLIB codec during decompression. /// /// /// q diff --git a/src/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs b/src/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs index 6a2744a546..3b58319963 100644 --- a/src/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs +++ b/src/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs @@ -488,7 +488,7 @@ public EncryptionAlgorithm Encryption /// - /// Size of the work buffer to use for the ZLIB codec during compression. + /// FontSize of the work buffer to use for the ZLIB codec during compression. /// /// /// diff --git a/src/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs b/src/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs index d5d32ad487..082bd8b832 100644 --- a/src/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs +++ b/src/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs @@ -239,7 +239,7 @@ static Config() // Number of bits by which ins_h must be shifted at each input // step. It must be such that after MIN_MATCH steps, the oldest - // byte no longer takes part in the hash key, that is: + // byte no longer takes part in the hash _key, that is: // hash_shift * MIN_MATCH >= hash_bits internal int hash_shift; @@ -294,7 +294,7 @@ static Config() internal int _lengthOffset; // index for literals or lengths - // Size of match buffer for literals/lengths. There are 4 reasons for + // FontSize of match buffer for literals/lengths. There are 4 reasons for // limiting lit_bufsize to 64K: // - frequencies can be kept in 16 bit counters // - if compression is not successful for the first block, all input diff --git a/src/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs b/src/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs index 3ab7cf0382..b5aafba373 100644 --- a/src/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs +++ b/src/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs @@ -304,7 +304,7 @@ public int InitializeInflate(int windowBits, bool expectRfc1950Header) /// ZlibCodec decompressor = new ZlibCodec(); /// /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); + /// Console.WriteLine("FontSize of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); /// MemoryStream ms = new MemoryStream(DecompressedBytes); /// /// int rc = decompressor.InitializeInflate(); @@ -528,7 +528,7 @@ private int _InternalInitializeDeflate(bool wantRfc1950Header) /// ZlibCodec compressor = new ZlibCodec(); /// /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); + /// Console.WriteLine("FontSize of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); /// MemoryStream ms = new MemoryStream(); /// /// int rc = compressor.InitializeDeflate(level); diff --git a/src/EPPlus/Properties/AssemblyInfo.cs b/src/EPPlus/Properties/AssemblyInfo.cs index e1c40e43c5..7d2f621091 100644 --- a/src/EPPlus/Properties/AssemblyInfo.cs +++ b/src/EPPlus/Properties/AssemblyInfo.cs @@ -19,9 +19,10 @@ Date Author Change // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: InternalsVisibleTo("EPPlusTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001001dd11308ec93a6ebcec727e183a8972dc6f95c23ecc34aa04f40cbfc9c17b08b4a0ea5c00dcd203bace44d15a30ce8796e38176ae88e960ceff9cc439ab938738ba0e603e3d155fc298799b391c004fc0eb4393dd254ce25db341eb43303e4c488c9500e126f1288594f0710ec7d642e9c72e76dd860649f1c48249c00e31fba")] +[assembly: InternalsVisibleTo("EPPlus.Export.Pdf.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100dd3a3466a88cbf5d374fe992cec433c48022414fe96608933e8e36782001213dd31bc454dc6f962a54a3a76cfb9e03a32cd4c658ecd49d1a98709971a080ab92d5c5b65346155f8d6422db4ffbf662f78913996a9a8b78ee11ff3cda7e585208cd4468fb3201f15bbb1dfc45c120703c9d6ad495bb9de66893ae5ab5ac8f40dc")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] - -// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: InternalsVisibleTo("EPPlus.DrawingRenderer.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010065aa00a9b0dcfa0e8debefb14c3b6c12ef658ce1cfbfafcb6eb7dbdc0c49e4f70ea144ba29d827453f0716ffc8c1d87450ce0cf255bda1def174915caaa78f373f291ce1a7edf91ba6f9dc961d937b19d46dd5d7d70a6e2097c749d43780f0d00b29a6f5aec5c1d191bee69de0c889a6d2566bef3cb235612351eae7015382d0")] +[assembly: InternalsVisibleTo("EPPlus.Graphics, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e9b33e79ac9cbb1ca1e0df0aa47d956404607d99cb28a5982f936de662eb2fd3d3459c5b625fe4791606113ff89ee8b915e1446d348be8c6b5106fd3ffde14cf337587920e1c76bebc3bfd95d7525f3a5bc384fb19f3c06306b8cd5ffbe4284c36d8285f16cc50e6b408a2e197229108ce683d865a946b92a324cfba8dbf57c2")] [assembly: Guid("9dd43b8d-c4fe-4a8b-ad6e-47ef83bbbb01")] // Version information for an assembly consists of the following four values: diff --git a/src/EPPlus/RichData/RichDataReferenceValueError.cs b/src/EPPlus/RichData/RichDataReferenceValueError.cs index d305fa32eb..db0093782e 100644 --- a/src/EPPlus/RichData/RichDataReferenceValueError.cs +++ b/src/EPPlus/RichData/RichDataReferenceValueError.cs @@ -14,7 +14,7 @@ public abstract class RichDataReferenceValueError : ExcelErrorValue /// Constructor /// /// Value metadata id - /// Rich Data Reference Type + /// Rich Data Reference BulletType internal RichDataReferenceValueError(uint vmId, RichDataReferenceTypes refType) : base(eErrorType.Value) { diff --git a/src/EPPlus/RichData/RichValueKeyFlags.cs b/src/EPPlus/RichData/RichValueKeyFlags.cs index 6a61ab654c..d36ec19300 100644 --- a/src/EPPlus/RichData/RichValueKeyFlags.cs +++ b/src/EPPlus/RichData/RichValueKeyFlags.cs @@ -24,23 +24,23 @@ namespace OfficeOpenXml.RichData internal enum RichValueKeyFlags { /// - /// False indicates that we hide this key value pair (KVP) in the default Card View + /// False indicates that we hide this _key value pair (KVP) in the default Card View /// ShowInCardView = 0x01, /// - /// False indicates that we hide this key value pair (KVP) from formulas and the object model + /// False indicates that we hide this _key value pair (KVP) from formulas and the object model /// ShowInDotNotation = 0x02, /// - /// False indicates that we hide this key value pair (KVP) from AutoComplete, sort, filter, and Find + /// False indicates that we hide this _key value pair (KVP) from AutoComplete, sort, filter, and Find /// ShowInAutoComplete = 0x04, /// - /// True indicates that we do not write this key value pair (KVP) into the file, it only exists in memory + /// True indicates that we do not write this _key value pair (KVP) into the file, it only exists in memory /// ExcludeFromFile = 0x08, /// - /// True indicates that we exclude this key value pair (KVP) when comparing rich values. + /// True indicates that we exclude this _key value pair (KVP) when comparing rich values. /// ExcludeFromCalcComparison = 0x10, } diff --git a/src/EPPlus/RichData/WebImages/WebImagesSupportingRichData.cs b/src/EPPlus/RichData/WebImages/WebImagesSupportingRichData.cs index 2b926839a1..5c67b595ea 100644 --- a/src/EPPlus/RichData/WebImages/WebImagesSupportingRichData.cs +++ b/src/EPPlus/RichData/WebImages/WebImagesSupportingRichData.cs @@ -138,7 +138,7 @@ private void ReadXml(XmlReader xr) public Uri MoreImagesAddress => _moreImagesAddressRel?.TargetUri; /// - /// BLIP (Binary Large Image or Picture). Uri to the local picture in the worksheet + /// BLIP (Binary Large BulletImage or Blip). Uri to the local picture in the worksheet /// public Uri Blip => _blipRel != null && _blipRel.TargetUri != null ? UriHelper.ResolvePartUri(_baseUri, _blipRel.TargetUri) : null; diff --git a/src/EPPlus/Sparkline/Enums.cs b/src/EPPlus/Sparkline/Enums.cs index 5b6fe203af..919cb9b109 100644 --- a/src/EPPlus/Sparkline/Enums.cs +++ b/src/EPPlus/Sparkline/Enums.cs @@ -36,7 +36,7 @@ public enum eDispBlanksAs Zero } /// - /// Type of sparkline + /// BulletType of sparkline /// public enum eSparklineType { diff --git a/src/EPPlus/Sparkline/ExcelSparklineGroup.cs b/src/EPPlus/Sparkline/ExcelSparklineGroup.cs index 5faa13bcba..4642fba4d3 100644 --- a/src/EPPlus/Sparkline/ExcelSparklineGroup.cs +++ b/src/EPPlus/Sparkline/ExcelSparklineGroup.cs @@ -297,7 +297,7 @@ public eDispBlanksAs DisplayEmptyCellsAs } const string _typePath = "@type"; /// - /// Type of sparkline + /// BulletType of sparkline /// public eSparklineType Type { diff --git a/src/EPPlus/Sparkline/ExcelSparklineGroupCollection.cs b/src/EPPlus/Sparkline/ExcelSparklineGroupCollection.cs index bd8944172c..7837120314 100644 --- a/src/EPPlus/Sparkline/ExcelSparklineGroupCollection.cs +++ b/src/EPPlus/Sparkline/ExcelSparklineGroupCollection.cs @@ -50,7 +50,7 @@ public int Count /// /// Adds a new sparklinegroup to the collection /// - /// Type of sparkline + /// BulletType of sparkline /// The location of the sparkline group. The range must have one row or column and must match the number of rows/columns in the datarange /// The data for the sparkline group /// diff --git a/src/EPPlus/Style/Dxf/ExcelDxfColor.cs b/src/EPPlus/Style/Dxf/ExcelDxfColor.cs index d49cc15566..328b7c6d1e 100644 --- a/src/EPPlus/Style/Dxf/ExcelDxfColor.cs +++ b/src/EPPlus/Style/Dxf/ExcelDxfColor.cs @@ -269,7 +269,7 @@ internal Color GetColorAsColor(bool whiteAsDefault = false) /// Return the RGB value as a string for the color object that uses the Indexed or Tint property /// /// The RGB color starting with a #FF (alpha) - internal string LookupColor() + internal string LookupColor(DxfStyleBase objectType = null) { if (Index >= 0 && Index < _styles.IndexedColors.Length) { @@ -283,8 +283,12 @@ internal string LookupColor() { return GetThemeColor(Theme.Value, Convert.ToDouble(Tint)); } - else if (Auto.Value) + else if (Auto != null && Auto.Value) { + if (objectType is ExcelDxfBorderItem) + { + return "#FF000000"; + } return GetThemeColor(eThemeSchemeColor.Background1, Convert.ToDouble(Tint)); } else @@ -294,7 +298,7 @@ internal string LookupColor() { c = ((int)(Math.Round((Tint.Value + 1) * 128))).ToString("X"); } - return "#FF" + c + c + c; + return "#FF" + c + c + c + c; } } diff --git a/src/EPPlus/Style/Dxf/ExcelDxfFontBase.cs b/src/EPPlus/Style/Dxf/ExcelDxfFontBase.cs index 47445778d2..2da82a02d8 100644 --- a/src/EPPlus/Style/Dxf/ExcelDxfFontBase.cs +++ b/src/EPPlus/Style/Dxf/ExcelDxfFontBase.cs @@ -49,7 +49,7 @@ public bool? Bold } bool? _italic; /// - /// Font Italic + /// Font FontItalic /// public bool? Italic { diff --git a/src/EPPlus/Style/Dxf/ExcelDxfGradientFill.cs b/src/EPPlus/Style/Dxf/ExcelDxfGradientFill.cs index 0f51828e93..bc2e859bc8 100644 --- a/src/EPPlus/Style/Dxf/ExcelDxfGradientFill.cs +++ b/src/EPPlus/Style/Dxf/ExcelDxfGradientFill.cs @@ -86,7 +86,7 @@ internal override DxfStyleBase Clone() } eDxfGradientFillType? _gradientType; /// - /// Type of gradient fill + /// BulletType of gradient fill /// public eDxfGradientFillType? GradientType { diff --git a/src/EPPlus/Style/ExcelColor.cs b/src/EPPlus/Style/ExcelColor.cs index 277cbca570..670610f295 100644 --- a/src/EPPlus/Style/ExcelColor.cs +++ b/src/EPPlus/Style/ExcelColor.cs @@ -122,7 +122,7 @@ private set /// /// The color public void SetColor(Color color) - { + { Rgb = color.ToArgb().ToString("X"); } /// @@ -197,6 +197,8 @@ private ExcelColorXml GetSource() return ((ExcelGradientFillXml)(_styles.Fills[Index])).GradientColor1; case eStyleClass.FillGradientColor2: return ((ExcelGradientFillXml)(_styles.Fills[Index])).GradientColor2; + case eStyleClass.FillGradientColor3: + return ((ExcelGradientFillXml)(_styles.Fills[Index])).GradientColor3; default: throw(new Exception("Invalid style-class for Color")); } @@ -209,16 +211,17 @@ internal override void SetIndex(int index) /// Return the RGB hex string for the Indexed or Tint property /// /// The RGB color starting with a #FF (alpha) - public string LookupColor() + public string LookupColor(StyleBase objectType = null) { - return LookupColor(this); + return LookupColor(this , objectType); } /// /// Return the RGB value as a string for the color object that uses the Indexed or Tint property /// /// The color object + /// The object type. Some objects has different default colors /// The RGB color starting with a #FF (alpha) - public string LookupColor(ExcelColor theColor) + public string LookupColor(ExcelColor theColor, StyleBase objectType = null) { if (theColor.Indexed >= 0 && theColor.Indexed < _styles.IndexedColors.Length) { @@ -230,19 +233,23 @@ public string LookupColor(ExcelColor theColor) { return "#" + theColor.Rgb; } - else if(theColor.Theme.HasValue) + else if (theColor.Theme.HasValue) { return GetThemeColor(theColor.Theme.Value, Convert.ToDouble(theColor.Tint)); } else if (theColor.Auto) { + if (objectType is Border || objectType is ExcelBorderItem) + { + return "#FF000000"; + } return GetThemeColor(eThemeSchemeColor.Background1, Convert.ToDouble(theColor.Tint)); } else { var s = theColor.GetSource(); if (!s.Exists) return string.Empty; - var c = ((int)(Math.Round((theColor.Tint+1) * 128))).ToString("X"); + var c = ((int)(Math.Round((theColor.Tint + 1) * 128))).ToString("X"); return "#FF" + c + c + c; } } @@ -294,5 +301,40 @@ internal static string GetThemeColor(eThemeSchemeColor theme, double tint, Excel } return "#" + color.ToArgb().ToString("X"); } + + internal bool IsEmpty() + { + if ( Index < 0 && + Theme == null && + Tint == 0d && + Rgb == null && + Auto == false && + Indexed < 0 ) + { + return true; + } + return false; + + } + + /// + /// Returns the resolved color as a , taking theme, tint, indexed, RGB, and auto values into account. + /// Returns if the color is not set. + /// + public Color ToColor() + { + var hex = LookupColor(); + if (string.IsNullOrEmpty(hex) || hex == "0") return Color.Empty; + + // LookupColor returns strings like "#FFRRGGBB". Strip the leading '#'. + if (hex[0] == '#') hex = hex.Substring(1); + + int argb; + if (int.TryParse(hex, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out argb)) + { + return Color.FromArgb(argb); + } + return Color.Empty; + } } } diff --git a/src/EPPlus/Style/ExcelFill.cs b/src/EPPlus/Style/ExcelFill.cs index f6504199bb..68cdd526b6 100644 --- a/src/EPPlus/Style/ExcelFill.cs +++ b/src/EPPlus/Style/ExcelFill.cs @@ -89,12 +89,12 @@ public ExcelColor BackgroundColor /// /// Access to properties for gradient fill. /// - public ExcelGradientFill Gradient + public ExcelGradientFill Gradient { get { if (_gradient == null) - { + { _gradient = new ExcelGradientFill(_styles, _ChangedEvent, _positionID, _address, Index); _backgroundColor = null; _patternColor = null; @@ -102,6 +102,15 @@ public ExcelGradientFill Gradient return _gradient; } } + + public bool HasGradient + { + get + { + return _styles.Fills[Index] is ExcelGradientFillXml; + } + } + internal override string Id { get @@ -153,6 +162,16 @@ public void SetBackground(eThemeSchemeColor color, ExcelFillStyle fillStyle = Ex PatternType = fillStyle; BackgroundColor.SetColor(color); } + + internal bool IsEmpty() + { + if( BackgroundColor.IsEmpty() && + PatternColor.IsEmpty() && + !HasGradient) + { + return true; + } + return false; + } } } - \ No newline at end of file diff --git a/src/EPPlus/Style/ExcelFont.cs b/src/EPPlus/Style/ExcelFont.cs index dd35f5b47c..f39b3e0e35 100644 --- a/src/EPPlus/Style/ExcelFont.cs +++ b/src/EPPlus/Style/ExcelFont.cs @@ -14,6 +14,7 @@ Date Author Change using System.Collections.Generic; using System.Text; using System.Drawing; +using OfficeOpenXml.Interfaces.Drawing.Text; namespace OfficeOpenXml.Style { @@ -57,7 +58,7 @@ private void CheckNormalStyleChange() } /// - /// The Size of the font + /// The FontSize of the font /// public float Size { @@ -268,6 +269,22 @@ public void SetFromFont(string name, float size, bool bold = false, bool italic Italic = italic; } + internal MeasurementFont GetMeasureFont() + { + var fontStyle = MeasurementFontStyles.Regular; + if (Bold) fontStyle |= MeasurementFontStyles.Bold; + if (UnderLine) fontStyle |= MeasurementFontStyles.Underline; + if (Italic) fontStyle |= MeasurementFontStyles.Italic; + if (Strike) fontStyle |= MeasurementFontStyles.Strikeout; + + return new MeasurementFont() + { + FontFamily = Name, + Size = Size, + Style = fontStyle + }; + } + internal override string Id { get diff --git a/src/EPPlus/Style/ExcelGradientFill.cs b/src/EPPlus/Style/ExcelGradientFill.cs index a5171ec419..16c02c7de7 100644 --- a/src/EPPlus/Style/ExcelGradientFill.cs +++ b/src/EPPlus/Style/ExcelGradientFill.cs @@ -171,6 +171,19 @@ public ExcelColor Color2 } } + ExcelColor _gradientColor3 = null; + internal ExcelColor Color3 + { + get + { + if (_gradientColor3 == null) + { + _gradientColor3 = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.FillGradientColor3, this); + } + return _gradientColor3; + + } + } internal override string Id { get { return Degree.ToString() + Type + Color1.Id + Color2.Id + Top.ToString() + Bottom.ToString() + Left.ToString() + Right.ToString(); } diff --git a/src/EPPlus/Style/ExcelTextFont.cs b/src/EPPlus/Style/ExcelTextFont.cs index 2cea39dfb2..416337815b 100644 --- a/src/EPPlus/Style/ExcelTextFont.cs +++ b/src/EPPlus/Style/ExcelTextFont.cs @@ -10,27 +10,38 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Xml; using OfficeOpenXml.Drawing; -using System.Drawing; using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Drawing.Style.Coloring; +using OfficeOpenXml.Drawing.Style.Font; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; +using OfficeOpenXml.Interfaces.Drawing.Text; +using OfficeOpenXml.Utils; +using OfficeOpenXml.Utils.EnumUtils; +using System; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Reflection.Emit; +using System.Xml; +using tc = OfficeOpenXml.Utils.TypeConversion; namespace OfficeOpenXml.Style { /// /// Used by Rich-text and Paragraphs. /// - public class ExcelTextFont : XmlHelper + public class ExcelTextFontXml : ExcelTextFont { + XmlHelper _xml; string _path; internal XmlNode _rootNode; Action _initXml; IPictureRelationDocument _pictureRelationDocument; - internal ExcelTextFont(IPictureRelationDocument pictureRelationDocument, XmlNamespaceManager namespaceManager, XmlNode rootNode, string path, string[] schemaNodeOrder, Action initXml=null) - : base(namespaceManager, rootNode) + internal ExcelTextFontXml(IPictureRelationDocument pictureRelationDocument, XmlNamespaceManager namespaceManager, XmlNode rootNode, string path, string[] schemaNodeOrder, Action initXml = null) : base(pictureRelationDocument) { - AddSchemaNodeOrder(schemaNodeOrder, new string[] { "bodyPr", "lstStyle","p", "pPr", "defRPr", "solidFill","highlight", "uFill", "latin","ea", "cs","sym","hlinkClick","hlinkMouseOver","rtl", "r", "rPr", "t" }); + _xml = XmlHelperFactory.Create(namespaceManager, rootNode); + _xml.AddSchemaNodeOrder(schemaNodeOrder, new string[] { "bodyPr", "lstStyle", "p", "pPr", "defRPr", "solidFill", "highlight", "uFill", "latin", "ea", "cs", "sym", "hlinkClick", "hlinkMouseOver", "rtl", "r", "rPr", "t" }); _rootNode = rootNode; _pictureRelationDocument = pictureRelationDocument; _initXml = initXml; @@ -39,57 +50,65 @@ internal ExcelTextFont(IPictureRelationDocument pictureRelationDocument, XmlName XmlNode node = rootNode.SelectSingleNode(path, namespaceManager); if (node != null) { - TopNode = node; + _xml.TopNode = node; + //topNode and current node becomes the same + //path = "."; } } _path = path; } + internal void TriggerCreateTopNodeOnTextSet() + { + CreateTopNode(); + } + + internal XmlHelper XmlHelper { get { return _xml; } } string _fontLatinPath = "a:latin/@typeface"; /// /// The latin typeface name /// - public string LatinFont + public override string LatinFont { get { - return GetXmlNodeString(_fontLatinPath); + return _xml.GetXmlNodeString(_fontLatinPath); } set { CreateTopNode(); - SetXmlNodeString(_fontLatinPath, value); + _xml.SetXmlNodeString(_fontLatinPath, value); } } string _fontEaPath = "a:ea/@typeface"; /// /// The East Asian typeface name /// - public string EastAsianFont + public override string EastAsianFont { get { - return GetXmlNodeString(_fontEaPath); + return _xml.GetXmlNodeString(_fontEaPath); } set { CreateTopNode(); - SetXmlNodeString(_fontEaPath, value); + _xml.SetXmlNodeString(_fontEaPath, value); } } string _fontCsPath = "a:cs/@typeface"; /// /// The complex font typeface name /// - public string ComplexFont + public override string ComplexFont { get { - return GetXmlNodeString(_fontCsPath); + return _xml.GetXmlNodeString(_fontCsPath); } set { CreateTopNode(); - SetXmlNodeString(_fontCsPath, value); + _xml.SetXmlNodeString(_fontCsPath, value); } } @@ -98,53 +117,53 @@ public string ComplexFont /// protected internal void CreateTopNode() { - if (_path!="" && TopNode==_rootNode) + if (_path != "" && _xml.TopNode == _rootNode) { _initXml?.Invoke(); - if (TopNode == _rootNode && string.IsNullOrEmpty(_path)==false) + if (_xml.TopNode == _rootNode && string.IsNullOrEmpty(_path) == false) { - CreateNode(_path); - TopNode = _rootNode.SelectSingleNode(_path, NameSpaceManager); - CreateNode("../../../a:bodyPr"); - CreateNode("../../../a:lstStyle"); + _xml.CreateNode(_path); + _xml.TopNode = _rootNode.SelectSingleNode(_path, _xml.NameSpaceManager); + _xml.CreateNode("../../../a:bodyPr"); + _xml.CreateNode("../../../a:lstStyle"); } } - else if (TopNode.ParentNode?.ParentNode?.ParentNode?.LocalName == "rich") + else if (_xml.TopNode.ParentNode?.ParentNode?.ParentNode?.LocalName == "rich") { - CreateNode("../../../a:bodyPr"); - CreateNode("../../../a:lstStyle"); + _xml.CreateNode("../../../a:bodyPr"); + _xml.CreateNode("../../../a:lstStyle"); } } string _boldPath = "@b"; /// /// If the font is bold /// - public bool Bold + public override bool Bold { get { - return GetXmlNodeBool(_boldPath); + return _xml.GetXmlNodeBool(_boldPath); } set { CreateTopNode(); - SetXmlNodeString(_boldPath, value ? "1" : "0"); + _xml.SetXmlNodeString(_boldPath, value ? "1" : "0"); } } string _underLinePath = "@u"; /// /// The fonts underline style /// - public eUnderLineType UnderLine + public override eUnderLineType UnderLine { get { - return GetXmlNodeString(_underLinePath).TranslateUnderline(); + return _xml.GetXmlNodeString(_underLinePath).TranslateUnderline(); } set { CreateTopNode(); - SetXmlNodeString(_underLinePath, value.TranslateUnderlineText()); + _xml.SetXmlNodeString(_underLinePath, value.TranslateUnderlineText()); } } @@ -153,97 +172,124 @@ internal void SetFromXml(XmlElement copyFromElement) CreateTopNode(); foreach (XmlAttribute a in copyFromElement.Attributes) { - ((XmlElement)TopNode).SetAttribute(a.Name, a.NamespaceURI, a.Value); + ((XmlElement)_xml.TopNode).SetAttribute(a.Name, a.NamespaceURI, a.Value); } - if(copyFromElement.HasChildNodes && !TopNode.HasChildNodes) + if (copyFromElement.HasChildNodes && !_xml.TopNode.HasChildNodes) { - TopNode.InnerXml = copyFromElement.InnerXml; + _xml.TopNode.InnerXml = copyFromElement.InnerXml; } } - string _underLineColorPath = "a:uFill/a:solidFill/a:srgbClr/@val"; + string _underLineColorPath = "a:uFill/a:solidFill"; + + ExcelDrawingColorManager _underlineColorManager = null; /// /// The fonts underline color /// - public Color UnderLineColor + public override Color UnderLineColor { get { - string col = GetXmlNodeString(_underLineColorPath); - if (col == "") + if(_underlineColorManager == null ) { - return Color.Empty; + _underlineColorManager = new ExcelDrawingColorManager(_xml.NameSpaceManager, _xml.TopNode, _underLineColorPath, _xml.SchemaNodeOrder); + } + if (_underlineColorManager.ColorType == eDrawingColorType.Scheme) + { + return tc.ColorConverter.GetThemeColor(_pictureRelationDocument.Package.Workbook.ThemeManager.GetOrCreateTheme(), _underlineColorManager); } else { - return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier)); + return _underlineColorManager.GetColor(); } } set { CreateTopNode(); - SetXmlNodeString(_underLineColorPath, value.ToArgb().ToString("X").Substring(2, 6)); + + if (_underlineColorManager == null) + { + _underlineColorManager = new ExcelDrawingColorManager(_xml.NameSpaceManager, _xml.TopNode, _underLineColorPath, _xml.SchemaNodeOrder); + } + _underlineColorManager.SetRgbColor(value); } } string _italicPath = "@i"; /// /// If the font is italic /// - public bool Italic + public override bool Italic { get { - return GetXmlNodeBool(_italicPath); + return _xml.GetXmlNodeBool(_italicPath); } set { CreateTopNode(); - SetXmlNodeString(_italicPath, value ? "1" : "0"); + _xml.SetXmlNodeString(_italicPath, value ? "1" : "0"); } } string _strikePath = "@strike"; /// /// Font strike out type /// - public eStrikeType Strike + public override eStrikeType Strike { get { - return GetXmlNodeString(_strikePath).TranslateStrikeType(); + return _xml.GetXmlNodeString(_strikePath).TranslateStrikeType(); } set { CreateTopNode(); - SetXmlNodeString(_strikePath, value.TranslateStrikeTypeText()); + _xml.SetXmlNodeString(_strikePath, value.TranslateStrikeTypeText()); } } string _sizePath = "@sz"; /// /// Font size /// - public float Size + public override float Size { get { - return GetXmlNodeInt(_sizePath) / 100; + var c = _xml.GetXmlNodeInt(_sizePath); + if (c == int.MinValue) + { + return c; + } + return c / 100F; } set { CreateTopNode(); - SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString()); + _xml.SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString()); } } + string _spacingPath = "@spc"; + public override double Spacing + { + get + { + return (_xml.GetXmlNodeDoubleNull(_spacingPath) ?? 0D) / 100; + } + set + { + _xml.SetXmlNodeDouble(_spacingPath, value * 100); + } + } ExcelDrawingFill _fill; /// /// A reference to the fill properties /// - public ExcelDrawingFill Fill + public override ExcelDrawingFill Fill { get { if (_fill == null) { - _fill = new ExcelDrawingFill(_pictureRelationDocument, NameSpaceManager, _rootNode, _path, SchemaNodeOrder, CreateTopNode); + _fill = new ExcelDrawingFill(_pictureRelationDocument, _xml.NameSpaceManager, _rootNode, _path, _xml.SchemaNodeOrder, CreateTopNode); } return _fill; } @@ -256,11 +302,11 @@ public ExcelDrawingFill Fill /// Use the Fill property for more options /// /// - public Color Color + public override Color Color { get { - string col = GetXmlNodeString(_colorPath); + string col = _xml.GetXmlNodeString(_colorPath); if (col == "") { return Color.Empty; @@ -280,19 +326,456 @@ public Color Color /// /// Specifies the minimum font size at which character kerning occurs for this text run /// - public double Kerning + public override double Kerning + { + get + { + return _xml.GetXmlNodeFontSize(_kernPath); + } + set + { + CreateTopNode(); + _xml.SetXmlNodeFontSize(_kernPath, value, "Kerning"); + } + } + /// + /// The capitalization that is to be applied + /// + public override eTextCapsType Capitalization + { + get + { + switch (_xml.GetXmlNodeString($"@cap")) + { + case "all": + return eTextCapsType.All; + case "small": + return eTextCapsType.Small; + default: + return eTextCapsType.None; + } + } + set + { + CreateTopNode(); + _xml.SetXmlNodeString($"@cap", value.ToEnumString()); + } + } + + /// + /// The baseline for both the superscript and subscript fonts in percentage + /// + public override double Baseline { get { - return GetXmlNodeFontSize(_kernPath); + return _xml.GetXmlNodePercentage($"@baseline") ?? 0; } set { CreateTopNode(); - SetXmlNodeFontSize(_kernPath, value, "Kerning"); + _xml.SetXmlNodePercentage($"@baseline", value); } } + internal void GetHeightInPixels(out float textWidth, out float textHeight, string text) + { + var tm = _pictureRelationDocument.Package.Settings.TextSettings.PrimaryTextMeasurer; + _pictureRelationDocument.Package.Workbook.Styles.GetNormalStyle(); + MeasurementFont f = GetMeasureFont(); + var b = tm.MeasureText(text, f); + textWidth = b.Width; + textHeight = b.Height; + } + internal override bool IsEmpty + { + get + { + return _xml.TopNode == null || (_rootNode == _xml.TopNode && string.IsNullOrEmpty(_path) == false) || (_xml.TopNode.ChildNodes.Count == 0 && _xml.TopNode.Attributes.Count == 0); + } + } + internal override XmlElement PathElement + { + get + { + var node = (XmlElement)_xml.GetNode(_path); + if (node == null) + { + return (XmlElement)_xml.CreateNode(_path); + } + else + { + return node; + } + } + } + + } + /// + /// Used by Rich-text and Paragraphs. + /// + public class ExcelTextFontRichText : ExcelTextFont + { + internal ExcelParagraphTextRunBase _textRun; + internal ExcelTextFontRichText(ExcelParagraphTextRunBase textRun) : base(textRun._prd) + { + _textRun = textRun; + } + /// + /// The latin typeface name + /// + public override string LatinFont + { + get + { + return _textRun.LatinFont; + } + set + { + _textRun.LatinFont = value; + } + } + /// + /// The East Asian typeface name + /// + public override string EastAsianFont + { + get + { + return _textRun.EastAsianFont; + } + set + { + _textRun.EastAsianFont = value; + } + } + /// + /// The complex font typeface name + /// + public override string ComplexFont + { + get + { + return _textRun.ComplexFont; + } + set + { + _textRun.ComplexFont = value; + } + } + + /// + /// If the font is bold + /// + public override bool Bold + { + get + { + return _textRun.FontBold; + } + set + { + _textRun.FontBold = value; + } + } + /// + /// The fonts underline style + /// + public override eUnderLineType UnderLine + { + get + { + return _textRun.FontUnderLine; + } + set + { + _textRun.FontUnderLine = value; + } + } + + /// + /// The fonts underline color + /// + public override Color UnderLineColor + { + get + { + return _textRun.UnderLineColor; + } + set + { + _textRun.UnderLineColor = value; + } + } + /// + /// If the font is italic + /// + public override bool Italic + { + get + { + return _textRun.FontItalic; + } + set + { + _textRun.FontItalic = value; + } + } + /// + /// Font strike out type + /// + public override eStrikeType Strike + { + get + { + return _textRun.FontStrike; + } + set + { + _textRun.FontStrike = value; + } + } + /// + /// Font size + /// + public override float Size + { + get + { + return _textRun.FontSize; + } + set + { + _textRun.FontSize = value; + } + } + /// + /// A reference to the fill properties + /// + public override ExcelDrawingFill Fill + { + get + { + return _textRun.Fill; + } + } + string _colorPath = "a:solidFill/a:srgbClr/@val"; + /// + /// Sets the default color of the text. + /// This sets the Fill to a SolidFill with the specified color. + /// + /// Use the Fill property for more options + /// + /// + public override Color Color + { + get + { + return _textRun.Fill.Color; + } + set + { + _textRun.Fill.Style = eFillStyle.SolidFill; + _textRun.Fill.SolidFill.Color.SetRgbColor(value); + } + } + /// + /// Specifies the minimum font size at which character kerning occurs for this text run + /// + public override double Kerning + { + get + { + return _textRun.Kerning; + } + set + { + _textRun.Kerning = value; + } + } + /// + /// The capitalization that is to be applied + /// + public override eTextCapsType Capitalization + { + get + { + return _textRun.Capitalization; + } + set + { + _textRun.Capitalization = value; + } + } + + /// + /// The baseline for both the superscript and subscript fonts in percentage + /// + public override double Baseline + { + get + { + return _textRun.Baseline; + } + set + { + _textRun.Baseline = value; + } + } + internal override bool IsEmpty => _textRun.IsEmpty; + internal override XmlElement PathElement => (XmlElement)_textRun.TopNode; + + /// + /// The spacing between characters within a text run. + /// + public override double Spacing + { + get + { + return _textRun.Spacing; + } + set + { + _textRun.Spacing = value; + } + } + } + /// + /// Used by Rich-text and Paragraphs. + /// + public abstract class ExcelTextFont + { + private IPictureRelationDocument _pictureRelationDocument; + + internal ExcelTextFont(IPictureRelationDocument pictureRelationDocument) + { + _pictureRelationDocument = pictureRelationDocument; + } + internal IPictureRelationDocument PictureRelationDocument { get => _pictureRelationDocument; } + /// + /// The latin typeface name + /// + public abstract string LatinFont + { + get; + set; + } + /// + /// The East Asian typeface name + /// + public abstract string EastAsianFont + { + get; + set; + } + /// + /// The complex font typeface name + /// + public abstract string ComplexFont + { + get; + set; + } + + /// + /// If the font is bold + /// + public abstract bool Bold + { + get; + set; + } + /// + /// The fonts underline style + /// + public abstract eUnderLineType UnderLine + { + get; + set; + } + + /// + /// The fonts underline color + /// + public abstract Color UnderLineColor + { + get; + set; + } + /// + /// If the font is italic + /// + public abstract bool Italic + { + get; + set; + } + /// + /// Font strike out type + /// + public abstract eStrikeType Strike + { + get; + set; + } + /// + /// Font size + /// + public abstract float Size + { + get; + set; + } + /// + /// A reference to the fill properties + /// + public abstract ExcelDrawingFill Fill + { + get; + } + /// + /// Sets the default color of the text. + /// This sets the Fill to a SolidFill with the specified color. + /// + /// Use the Fill property for more options + /// + /// + public abstract Color Color + { + get; + set; + } + /// + /// Specifies the minimum font size at which character kerning occurs for this text run + /// + public abstract double Kerning + { + get; + set; + } + /// + /// The capitalization that is to be applied + /// + public abstract eTextCapsType Capitalization + { + get; + set; + } + + /// + /// The baseline for both the superscript and subscript fonts in percentage + /// + public abstract double Baseline + { + get; + set; + } + public abstract double Spacing + { + get; + set; + } + /// /// Set the font style properties /// @@ -312,5 +795,57 @@ public void SetFromFont(string name, float size, bool bold = false, bool italic if (underline) UnderLine = eUnderLineType.Single; if (strikeout) Strike = eStrikeType.Single; } + + internal MeasurementFont GetMeasureFont() + { + return FontUtil.GetMeasureFont(LatinFont, ComplexFont, EastAsianFont, Size, GetFontStyle(), _pictureRelationDocument.Package); + } + + private MeasurementFontStyles GetFontStyle() + { + MeasurementFontStyles ret = MeasurementFontStyles.Regular; + if (Bold) + { + ret |= MeasurementFontStyles.Bold; + } + if (Italic) + { + ret |= MeasurementFontStyles.Italic; + } + if (UnderLine != eUnderLineType.None) + { + ret |= MeasurementFontStyles.Underline; + } + return ret; + } + /// + /// Returns the text according to the capitalization settings. + /// + /// The text + /// If Capitalization is None, the original text is returned. If Capitalization is All, the text is converted to upper case. If Capitalization is Small, the text is converted to lower case. + internal string GetCapitalizedText(string text) + { + if (Capitalization == eTextCapsType.All) + { + return text.ToUpper(CultureInfo.InvariantCulture); + } + else if (Capitalization == eTextCapsType.Small) + { + return text.ToLower(CultureInfo.InvariantCulture); + } + else + { + return text; + } + } + + internal abstract bool IsEmpty + { + get; + } + internal abstract XmlElement PathElement + { + get; + } } } diff --git a/src/EPPlus/Style/HeaderFooterTextFormat/ExcelHeaderFooterTextCollection.cs b/src/EPPlus/Style/HeaderFooterTextFormat/ExcelHeaderFooterTextCollection.cs index d544ea3c36..f6e45ba7df 100644 --- a/src/EPPlus/Style/HeaderFooterTextFormat/ExcelHeaderFooterTextCollection.cs +++ b/src/EPPlus/Style/HeaderFooterTextFormat/ExcelHeaderFooterTextCollection.cs @@ -1,14 +1,24 @@ -using OfficeOpenXml.Drawing; +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 8 + *************************************************************************************************/ +using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Vml; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Finance; -using OfficeOpenXml.Utils.TypeConversion; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; -using System.Text; + namespace OfficeOpenXml.Style.HeaderFooterTextFormat { /// @@ -605,7 +615,7 @@ internal void ReadHeaderFooterFormat(string hfText) } break; default: - //Font Size + //Font FontSize if (char.IsDigit(hfText[i])) { int num = i; diff --git a/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatToken.cs b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatToken.cs new file mode 100644 index 0000000000..449e80fa85 --- /dev/null +++ b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatToken.cs @@ -0,0 +1,25 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Style +{ + internal class NumberFormatToken + { + public NumberFormatTokenType TokenType { get; set; } + public string Value { get; set; } + public NumberFormatToken(NumberFormatTokenType tokenType, string value) + { + TokenType = tokenType; + Value = value; + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenType.cs b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenType.cs new file mode 100644 index 0000000000..e2e40bab32 --- /dev/null +++ b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenType.cs @@ -0,0 +1,37 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +namespace OfficeOpenXml.Style +{ + public enum NumberFormatTokenType + { + NumberFormat, + DateTimeFormat, + Semicolon, + String, + StringContent, + LanguageCalenderString, + CharacterWidth, + Text, //A literal text token, not inside a string. + Color, + Condition, + ElapsedTime, + /// + /// The parsed token represents an opening bracket ('[') + /// + OpeningBracket, + /// + /// The parsed token represents a closing bracket (']') + /// + ClosingBracket, + } +} \ No newline at end of file diff --git a/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenizer.cs b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenizer.cs new file mode 100644 index 0000000000..80edbfa6d7 --- /dev/null +++ b/src/EPPlus/Style/NumberFormatTokenizer/NumberFormatTokenizer.cs @@ -0,0 +1,144 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OfficeOpenXml.Style +{ + internal class NumberFormatTokenizer + { + internal static IList Tokenize(string input) + { + var tokens = new List(); + bool isInString = false; + var value = new StringBuilder(); + for (int i=0;i0 && input[i - 1]=='\\') + { + //Escaped quote + value.Append(c); + i++; + continue; + } + isInString = false; + tokens.Add(new NumberFormatToken(NumberFormatTokenType.StringContent, value.ToString())); + value = new StringBuilder(); + tokens.Add(new NumberFormatToken(NumberFormatTokenType.String, c.ToString())); + } + else + { + value.Append(c); + } + + continue; + } + switch(c) + { + case '"': + tokens.Add(new NumberFormatToken(NumberFormatTokenType.Text, value.ToString())); + if (value.Length > 0) + { + value = new StringBuilder(); + } + isInString = true; + continue; + case '[': + tokens.Add(new NumberFormatToken(NumberFormatTokenType.OpeningBracket, c.ToString())); + continue; + case ']': + HandleBracketContent(ref value, tokens); + tokens.Add(new NumberFormatToken(NumberFormatTokenType.ClosingBracket, c.ToString())); + break; + case ';': + var v = value.ToString(); + tokens.Add(new NumberFormatToken(GetTokenTypeFromValue(v), v)); + tokens.Add(new NumberFormatToken(NumberFormatTokenType.Semicolon, c.ToString())); + break; + case '_': + if (i + 1 < input.Length) + { + tokens.Add(new NumberFormatToken(NumberFormatTokenType.CharacterWidth, input[i + 1].ToString())); + i++; + } + else + { + throw (new InvalidOperationException("Invalid number format string. Ending with a _ is not valid")); + } + break; + default: + value.Append(c); + break; + } + } + return tokens; + } + + private static NumberFormatTokenType GetTokenTypeFromValue(string v) + { + if(v.IndexOfAny(new char[] { 'y', 'd','m', 'h', 's' }, 0)>=0 && v.IndexOfAny(new char[] { '0', '#', '?'})<0) + { + return NumberFormatTokenType.DateTimeFormat; + } + else + { + return NumberFormatTokenType.NumberFormat; + } + } + + internal static HashSet FormatColors = new HashSet( + new string[]{ + "black", + "blue", + "cyan", + "green", + "magenta", + "red", + "white", + "yellow" + }, StringComparer.OrdinalIgnoreCase); + + private static void HandleBracketContent(ref StringBuilder value, List tokens) + { + var v = value.ToString(); + if (FormatColors.Contains(v)) + { + tokens.Add(new NumberFormatToken(NumberFormatTokenType.Color, v)); + } + else if (v.StartsWith("=") || + v.StartsWith(">") || + v.StartsWith("<")) + { + tokens.Add(new NumberFormatToken(NumberFormatTokenType.Condition, v)); + } + else if (v.StartsWith("$") || v.StartsWith("0xf")) + { + tokens.Add(new NumberFormatToken(NumberFormatTokenType.LanguageCalenderString, v)); + } + else if (v.StartsWith("h") || v.StartsWith("m") || v.StartsWith("s")) + { + tokens.Add(new NumberFormatToken(NumberFormatTokenType.ElapsedTime, v)); + } + else + { + throw (new InvalidOperationException("Invalid format inside brackaets[]")); + } + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Style/RichText/ExcelLineSpacing.cs b/src/EPPlus/Style/RichText/ExcelLineSpacing.cs new file mode 100644 index 0000000000..9c6d9abc14 --- /dev/null +++ b/src/EPPlus/Style/RichText/ExcelLineSpacing.cs @@ -0,0 +1,183 @@ +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace OfficeOpenXml.Style +{ + + /// + /// Used to define line-spacing in pargraphs/shapes + /// Default is single line spacing + /// + public class ExcelLineSpacing : XmlHelper + { + Action _initXml; + string _path, _subPath; + eDrawingTextLineSpacing _defTls; + internal ExcelLineSpacing(XmlNamespaceManager nsm, XmlNode topNode,string path, string[] schemaNodeOrder, Action initXml, eDrawingTextLineSpacing defTls) : base(nsm, topNode) + { + _path = path; + _initXml = initXml; + SchemaNodeOrder = schemaNodeOrder; + var node = GetNode(path); + _defTls = defTls; + if (node==null || node.HasChildNodes==false) + { + return; + } + else if (node.ChildNodes[0].LocalName== "spcPts") + { + _subPath = "/a:spcPts"; + _lineSpacingType = eDrawingTextLineSpacing.Exactly; + } + else + { + _subPath = "/a:spcPct"; + _lineSpacingType = eDrawingTextLineSpacing.Multiple; + } + } + + /// + /// Value for the line spacing. + /// If the value is the value is in points. + /// Otherwise the value is in percent. Default is 100 percent. + /// + public double Value + { + get + { + var v = GetXmlNodeDoubleNull($"{_path}{_subPath}/@val"); + if (v.HasValue) + { + if (_lineSpacingType == eDrawingTextLineSpacing.Exactly) + { + return v.Value / 100; + } + else + { + return v.Value / 1000; + } + } + else + { + if(_defTls==eDrawingTextLineSpacing.Single) + { + return 100; + } + else + { + return 0; + } + } + } + set + { + if(_initXml != null) + { + _initXml.Invoke(); + } + SetXmlNodeInt($"{_path}{_subPath}/@val", GetXmlValue(value)); + } + } + + private int GetXmlValue(double value) + { + if(_lineSpacingType==eDrawingTextLineSpacing.Exactly) + { + return (int)(value * 100); + } + else + { + return (int)(value * 1000); + } + } + + eDrawingTextLineSpacing? _lineSpacingType; + /// + /// If setting Exactly or Multiple it is recommended to use + /// SetExactly or SetMultiple functions. + /// Otherwise they are set to default values 13.2 or 3 + /// + public eDrawingTextLineSpacing LineSpacingType + { + get + { + return _lineSpacingType ?? _defTls; + } + set + { + if (value == LineSpacingType) return; + + switch (_lineSpacingType) + { + case eDrawingTextLineSpacing.Exactly: + SetExactly(13.2); + break; + case eDrawingTextLineSpacing.Multiple: + SetMultiple(300); + break; + case eDrawingTextLineSpacing.Double: + SetMultiple(200); + break; + case eDrawingTextLineSpacing.Single: + SetMultiple(100); + break; + case eDrawingTextLineSpacing.OneAndAHalf: + SetMultiple(150); + break; + } + } + } + + /// + /// Sets line spacing to Exactly inPoints + /// + /// + public void SetExactly(double inPoints) + { + if(LineSpacingType != eDrawingTextLineSpacing.Exactly) + { + DeleteNode($"{_path}{_subPath}"); + _subPath = "/a:spcPts"; + } + _lineSpacingType = eDrawingTextLineSpacing.Exactly; + Value = inPoints; + } + /// + /// Sets line spacing to multiple of percent + /// + /// + public void SetMultiple(double percent) + { + if (_lineSpacingType == eDrawingTextLineSpacing.Exactly) + { + DeleteNode($"{_path}{_subPath}"); + _subPath = "/a:spcPct"; + } + _lineSpacingType = eDrawingTextLineSpacing.Multiple; + Value = percent; + } + + ///// + ///// If setting Exactly or Multiple it is recommended to use + ///// SetExactly or SetMultiple functions. + ///// Otherwise they are set to default values 13.2 or 3 + ///// + ///// + //public void SetSpacingType(DrawingTextLineSpacing lineSpacingType) + //{ + // LineSpacingType = lineSpacingType; + // if(lineSpacingType == DrawingTextLineSpacing.Exactly) + // { + // SetExactly(13.2); + // } + // else if(lineSpacingType == DrawingTextLineSpacing.Multiple) + // { + // SetMultiple(3); + // } + //} + } +} diff --git a/src/EPPlus/Style/RichText/ExcelParagraph.cs b/src/EPPlus/Style/RichText/ExcelParagraph.cs index e90136448e..70138580bc 100644 --- a/src/EPPlus/Style/RichText/ExcelParagraph.cs +++ b/src/EPPlus/Style/RichText/ExcelParagraph.cs @@ -11,7 +11,9 @@ Date Author Change 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Controls; using OfficeOpenXml.Drawing.Interfaces; +using OfficeOpenXml.Utils.EnumUtils; using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using System; using System.Collections.Generic; @@ -21,17 +23,46 @@ Date Author Change namespace OfficeOpenXml.Style { /// - /// Handels paragraph text + /// Handles paragraph text /// - public sealed class ExcelParagraph : ExcelTextFont + public sealed class ExcelParagraph : ExcelTextFontRichText { - internal ExcelParagraph(IPictureRelationDocument pictureRelationDocument, XmlNamespaceManager ns, XmlNode rootNode, string path, string[] schemaNodeOrder) : - base(pictureRelationDocument, ns, rootNode, path + "a:rPr", schemaNodeOrder) - { - + internal ExcelParagraph(ExcelParagraphTextRunBase textRun) : + base(textRun) + { } - const string TextPath = "../a:t"; + const string AligPath = "../../a:pPr/@algn"; const string FldPath = "../a:fld"; + /// + /// Text + /// + public eTextAlignment HorizontalAlignment + { + get + { + return _textRun.Paragraph.HorizontalAlignment; + } + set + { + _textRun.Paragraph.HorizontalAlignment = value; + } + } + const string IndentLevelPath = "../../a:pPr/@lvl"; + /// + /// Indent level for the paragraph. Ranges from 0-8; + /// + public int? IndentLevel + { + get + { + return _textRun.Paragraph.IndentLevel; + } + set + { + _textRun.Paragraph.IndentLevel = value ?? 0; + } + } + /// /// Text /// @@ -39,30 +70,42 @@ public string Text { get { - return GetXmlNodeString(TextPath); + return _textRun.Text; } set { - CreateTopNode(); - SetXmlNodeString(TextPath, value); + _textRun.Text = value; } } /// - /// If the paragraph is the first in the collection + /// Text, adjusted for the Capitalization property /// - public bool IsFirstInParagraph + public string DisplayedText { get { - var parent = _rootNode.ParentNode; - for (int i=0;i + /// If the paragraph is the first in the collection + /// + public bool IsFirstInParagraph + { + get + { + return _textRun.IsFirstInParagraph; } } /// @@ -72,16 +115,17 @@ public bool IsLastInParagraph { get { - var parent = _rootNode.ParentNode; - for (int i = parent.ChildNodes.Count-1; i >=0 ; i--) - { - if (parent.ChildNodes[i].LocalName == "r") - { - return parent.ChildNodes[i] == _rootNode; - } - } - return false; + return _textRun.IsLastInParagraph; } } + + internal bool IsInParagraph(ExcelDrawingParagraph paragraph) + { + return _textRun.Paragraph.Equals(paragraph); + } + internal bool IsTextRun(ExcelParagraphTextRunBase paragraph) + { + return _textRun.Equals(paragraph); + } } } diff --git a/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs b/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs index b9419e357f..2b6bb55d34 100644 --- a/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs +++ b/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs @@ -15,11 +15,11 @@ Date Author Change using System.Collections.Generic; using System.Drawing; using System.Globalization; +using OfficeOpenXml.Interfaces.Drawing.Text; using System.IO; using System.Linq; using System.Text; using System.Xml; - namespace OfficeOpenXml.Style { /// @@ -30,34 +30,72 @@ public class ExcelParagraphCollection : XmlHelper, IEnumerable List _list = new List(); private readonly ExcelDrawing _drawing; private readonly string _path; - private readonly List _paragraphs=new List(); private readonly float _defaultFontSize; - internal ExcelParagraphCollection(ExcelDrawing drawing, XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder, float defaultFontSize =11) : + private readonly ExcelTextFont _defaultFont; + private readonly ExcelTextBody _textBody; + internal ExcelParagraphCollection(ExcelTextBody tb, ExcelDrawing drawing, XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder, float defaultFontSize = 11, eTextAlignment defaultAlignment = eTextAlignment.Left) : base(ns, topNode) { _drawing = drawing; + _textBody = tb; _defaultFontSize = defaultFontSize; - AddSchemaNodeOrder(schemaNodeOrder, new string[] { "strRef","rich", "f", "strCache", "bodyPr", "lstStyle", "p", "ptCount","pt","pPr", "lnSpc", "spcBef", "spcAft", "buClrTx", "buClr", "buSzTx", "buSzPct", "buSzPts", "buFontTx", "buFont","buNone", "buAutoNum", "buChar","buBlip", "tabLst","defRPr", "r","br","fld" ,"endParaRPr" }); - + AddSchemaNodeOrder(schemaNodeOrder, new string[] { "strRef", "rich", "f", "strCache", "bodyPr", "lstStyle", "p", "ptCount", "pt", "pPr", "lnSpc", "spcBef", "spcAft", "buClrTx", "buClr", "buSzTx", "buSzPct", "buSzPts", "buFontTx", "buFont", "buNone", "buAutoNum", "buChar", "buBlip", "tabLst", "defRPr", "r", "br", "fld", "endParaRPr" }); _path = path; - var pars = TopNode.SelectNodes(path, NameSpaceManager); - foreach(XmlElement par in pars) + + foreach (var p in tb.Paragraphs) { - _paragraphs.Add(par); - var nl = par.SelectNodes("a:r", NameSpaceManager); - if (nl != null) + p.defaultAlignment = defaultAlignment; + foreach (var tr in p.TextRuns) { - foreach (XmlNode n in nl) - { - if (_list.Count == 0 || n.ParentNode != _list[_list.Count - 1].TopNode.ParentNode) - { - _paragraphs.Add((XmlElement)n.ParentNode); - } - _list.Add(new ExcelParagraph(drawing._drawings, ns, n, "", schemaNodeOrder)); - } + _list.Add(new ExcelParagraph(tr)); + } + } + tb.Paragraphs.SetUpdateCallbacks(AddParagraph, RemoveParagraph, RemoveTextRun); + var paths = path.Split('/'); + } + + private void AddParagraph(ExcelParagraphTextRunBase tr) + { + bool inParagraph = false; + for (int i=0;i < _list.Count;i++) + { + var item = _list[i]; + if(item._textRun.Paragraph==tr.Paragraph) + { + inParagraph = true; + } + else if(inParagraph) + { + _list.Insert(i - 1, new ExcelParagraph(tr)); + return; + } + } + _list.Add(new ExcelParagraph(tr)); + } + private void RemoveTextRun(ExcelParagraphTextRunBase textRun) + { + for(int i=0;i /// The indexer for this collection /// @@ -84,70 +122,35 @@ public int Count /// Add a rich text string /// /// The text to add - /// This will be a new line. Is ignored for first item added to the collection + /// This will be a new line. /// public ExcelParagraph Add(string Text, bool NewParagraph=false) { - XmlDocument doc; - if (TopNode is XmlDocument) + ExcelDrawingParagraph p; + if (NewParagraph || _textBody.Paragraphs.Count==0) { - doc = TopNode as XmlDocument; + _textBody.Paragraphs.Add(Text); } else { - doc = TopNode.OwnerDocument; - } - XmlNode parentNode; - if(NewParagraph && _list.Count!=0) - { - parentNode = CreateNode(_path, false, true); - _paragraphs.Add((XmlElement)parentNode); - var p = _list[0].TopNode.ParentNode.ParentNode.SelectSingleNode("a:pPr", NameSpaceManager); - if(p!=null) - { - parentNode.InnerXml = p.OuterXml; - } - } - else if(_paragraphs.Count > 1) - { - parentNode = _paragraphs[_paragraphs.Count - 1]; - } - else - { - parentNode = CreateNode(_path); - _paragraphs.Add((XmlElement)parentNode); - var defNode = CreateNode(_path + "/a:pPr/a:defRPr"); - if (defNode.InnerXml == "") - { - ((XmlElement)defNode).SetAttribute("sz", (_defaultFontSize*100).ToString(CultureInfo.InvariantCulture)); - var normalStyle = _drawing._drawings.Worksheet.Workbook.Styles.GetNormalStyle(); - if (normalStyle == null) - defNode.InnerXml = ""; - else - defNode.InnerXml = $""; - } + p = _textBody.Paragraphs[_textBody.Paragraphs.Count - 1]; + p.TextRuns.Add(Text); } - var node = doc.CreateElement("a", "r", ExcelPackage.schemaDrawings); - parentNode.AppendChild(node); - var childNode = doc.CreateElement("a", "rPr", ExcelPackage.schemaDrawings); - node.AppendChild(childNode); - var rt = new ExcelParagraph(_drawing._drawings, NameSpaceManager, node, "", SchemaNodeOrder); - rt.Text = Text; - _list.Add(rt); - return rt; + return _list[_list.Count-1]; } /// /// Removes all items in the collection /// public void Clear() { - for (int ix = 0 ; ix < _paragraphs.Count; ix++) - { - _paragraphs[ix].ParentNode?.RemoveChild(_paragraphs[ix]); - } + //for (int ix = 0 ; ix < _paragraphs.Count; ix++) + //{ + // _paragraphs[ix].ParentNode?.RemoveChild(_paragraphs[ix]); + //} + _textBody.Paragraphs.Clear(); _list.Clear(); - _paragraphs.Clear(); + //_paragraphs.Clear(); } /// /// Remove the item at the specified index @@ -155,13 +158,14 @@ public void Clear() /// The index public void RemoveAt(int Index) { - var node = _list[Index].TopNode; - while (node != null && node.Name != "a:r") - { - node = node.ParentNode; - } - node.ParentNode.RemoveChild(node); - _list.RemoveAt(Index); + Remove(_list[Index]); + //var node = _list[Index].TopNode; + //while (node != null && node.Name != "a:r") + //{ + // node = node.ParentNode; + //} + //node.ParentNode.RemoveChild(node); + //_list.RemoveAt(Index); } /// /// Remove the specified item @@ -169,7 +173,12 @@ public void RemoveAt(int Index) /// The item public void Remove(ExcelParagraph Item) { - TopNode.RemoveChild(Item.TopNode); + var p = Item._textRun.Paragraph; + p.TextRuns.Remove(Item._textRun); + if (p.TextRuns.Count == 0 && _textBody.Paragraphs.Count != 0) + { + _textBody.Paragraphs.Remove(p); + } } /// /// The full text @@ -190,31 +199,70 @@ public string Text sb.Append(item.Text); } } + var ret = sb.ToString(); if (ret.EndsWith(Environment.NewLine)) { //Remove last NewLine return ret.Substring(0, ret.Length - Environment.NewLine.Length); } + return ret; } set { - if (Count == 0) + if (_textBody.Paragraphs.Count == 0) { - Add(value); + //_textBody.Paragraphs.Add(value); + Add(value, true); } else { - this[0].Text = value; - for (int ix = _list.Count - 1; ix > 0; ix--) + if (Count == 0) { - RemoveAt(ix); + _textBody.Paragraphs[0].TextRuns.Add(value); + } + else + { + this[0].Text = value; + for (int ix = _list.Count - 1; ix > 0; ix--) + { + RemoveAt(ix); + } } } } } + /// + /// The displayed test adjusted for capitalization. + /// + public string DisplayedText + { + get + { + StringBuilder sb = new StringBuilder(); + foreach (var item in _list) + { + if (item.IsLastInParagraph) + { + sb.AppendLine(item.DisplayedText); + } + else + { + sb.Append(item.DisplayedText); + } + } + + var ret = sb.ToString(); + if (ret.EndsWith(Environment.NewLine)) + { + //Remove last NewLine + return ret.Substring(0, ret.Length - Environment.NewLine.Length); + } + return ret; + } + } #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() @@ -232,5 +280,38 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() } #endregion + + //internal void UpdateXmlEndParagraphRunProperties() + //{ + // if (_list.Count > 1) + // { + // for (int i = 1; i < _list.Count; i++) + // { + // //Get the run node of previous paragraph if it exists + // var prevRunNode = _list[i-1].TopNode; + // if (prevRunNode != null) + // { + // var endParaNode = _list[i].TopNode.SelectSingleNode("../../a:endParaRPr", NameSpaceManager); + + // if(endParaNode != null) + // { + // endParaNode.ParentNode.RemoveChild(endParaNode); + // } + + // endParaNode = _list[i].CreateNode("../../a:endParaRPr"); + + // foreach(XmlAttribute attribute in prevRunNode.Attributes) + // { + // endParaNode.Attributes.Append((XmlAttribute)attribute.Clone()); + // } + + // foreach(XmlNode childnode in prevRunNode.ChildNodes) + // { + // endParaNode.AppendChild(childnode.Clone()); + // } + // } + // } + // } + //} } } diff --git a/src/EPPlus/Style/RichText/ExcelRichText.cs b/src/EPPlus/Style/RichText/ExcelRichText.cs index 9d3e82a389..57a8fec814 100644 --- a/src/EPPlus/Style/RichText/ExcelRichText.cs +++ b/src/EPPlus/Style/RichText/ExcelRichText.cs @@ -1,4 +1,4 @@ -/************************************************************************************************* + /************************************************************************************************* Required Notice: Copyright (C) EPPlus Software AB. This software is licensed under PolyForm Noncommercial License 1.0.0 and may only be used for noncommercial purposes @@ -10,17 +10,19 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ -using System; -using System.Text; -using System.Xml; -using System.Drawing; -using System.Globalization; -using OfficeOpenXml.Export.HtmlExport; +using EPPlus.Fonts.OpenType.Integration.DataHolders; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Style.Coloring; -using OfficeOpenXml.Utils.TypeConversion; +using OfficeOpenXml.Export.HtmlExport; +using OfficeOpenXml.Interfaces.RichText; using OfficeOpenXml.Utils.AttributesUtils; using OfficeOpenXml.Utils.EnumUtils; +using OfficeOpenXml.Utils.TypeConversion; +using System; +using System.Drawing; +using System.Globalization; +using System.Text; +using System.Xml; namespace OfficeOpenXml.Style { @@ -31,7 +33,7 @@ namespace OfficeOpenXml.Style public class ExcelRichText { /// - /// A referens to the richtext collection + /// A reference to the richtext collection /// internal ExcelRichTextCollection _collection { get; set; } @@ -42,17 +44,17 @@ public class ExcelRichText public bool PreserveSpace { get; set; } = true; /// - /// Bold text + /// FontBold text /// public bool Bold { get; set; } = false; /// - /// Italic text + /// FontItalic text /// public bool Italic { get; set; } = false; /// - /// Strike-out text + /// FontStrike-out text /// public bool Strike { get; set; } = false; @@ -586,5 +588,15 @@ public bool HasDefaultValue //Scheme == null; } } + + /// + /// Export to OpenTypeFormat + /// + /// + public IRichTextFormatEssential ExportToOpenTypeFormat() + { + var rtBase = new RichTextFormatBase(Text, _collection._cells.Style.Font.Name, Size, Bold, Italic); + return rtBase; + } } } diff --git a/src/EPPlus/Style/RichText/ExcelRichTextCollection.cs b/src/EPPlus/Style/RichText/ExcelRichTextCollection.cs index 0cf46fd11e..d5af6c257c 100644 --- a/src/EPPlus/Style/RichText/ExcelRichTextCollection.cs +++ b/src/EPPlus/Style/RichText/ExcelRichTextCollection.cs @@ -77,7 +77,7 @@ internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode textElem, Excel _cells= cells; _isComment = true; - foreach (XmlNode rElement in textElem.ChildNodes) + foreach (XmlElement rElement in textElem.ChildNodes) { if(rElement.LocalName == "r") { @@ -204,6 +204,10 @@ public ExcelRichText Insert(int index, string text) rt.Italic = style.Font.Italic; rt.PreserveSpace = true; rt.UnderLine = style.Font.UnderLine; + rt.Strike = style.Font.Strike; + rt.VerticalAlign = style.Font.VerticalAlign; + rt.Family = style.Font.Family; + rt.Charset = style.Font.Charset != null ? (int)style.Font.Charset : 1; int hex; var s = _cells.Worksheet.GetStyleInner(_cells._fromRow, _cells._fromCol); var fnt = _cells.Worksheet.Workbook.Styles.GetStyleObject(s, _cells.Worksheet.PositionId, ExcelAddressBase.GetAddress(_cells._fromRow, _cells._fromCol)).Font; diff --git a/src/EPPlus/Style/RichText/eDrawingTextLineSpacing.cs b/src/EPPlus/Style/RichText/eDrawingTextLineSpacing.cs new file mode 100644 index 0000000000..335cfbde8c --- /dev/null +++ b/src/EPPlus/Style/RichText/eDrawingTextLineSpacing.cs @@ -0,0 +1,29 @@ +namespace OfficeOpenXml.Style +{ + /// + /// Line spacing + /// + public enum eDrawingTextLineSpacing + { + /// + /// Single line spacing + /// + Single, + /// + /// 1.5 lines + /// + OneAndAHalf, + /// + /// Double line spacing + /// + Double, + /// + /// Exact point spacing + /// + Exactly, + /// + /// Multiple line spacing + /// + Multiple + } +} diff --git a/src/EPPlus/Style/Table/ExcelTableNamedStyleBase.cs b/src/EPPlus/Style/Table/ExcelTableNamedStyleBase.cs index afd6681ae2..da6bc313d9 100644 --- a/src/EPPlus/Style/Table/ExcelTableNamedStyleBase.cs +++ b/src/EPPlus/Style/Table/ExcelTableNamedStyleBase.cs @@ -33,19 +33,16 @@ internal ExcelTableNamedStyleBase(XmlNamespaceManager nameSpaceManager, XmlNode { _styles = styles; As = new ExcelTableNamedStyleAsType(this); - foreach(XmlNode node in topNode.ChildNodes) + foreach(XmlElement e in topNode.ChildNodes) { - if (node is XmlElement e) + var type = e.GetAttribute("type").ToEnum(eTableStyleElement.WholeTable); + if (IsBanded(type)) { - var type = e.GetAttribute("type").ToEnum(eTableStyleElement.WholeTable); - if (IsBanded(type)) - { - _dic.Add(type, new ExcelBandedTableStyleElement(nameSpaceManager, node, styles, type)); - } - else - { - _dic.Add(type, new ExcelTableStyleElement(nameSpaceManager, node, styles, type)); - } + _dic.Add(type, new ExcelBandedTableStyleElement(nameSpaceManager, e, styles, type)); + } + else + { + _dic.Add(type, new ExcelTableStyleElement(nameSpaceManager, e, styles, type)); } } } diff --git a/src/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs b/src/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs index d52f5ea702..91eb6ed340 100644 --- a/src/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs +++ b/src/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs @@ -35,7 +35,8 @@ internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode) : Type = GetXmlNodeString(_typePath)=="path" ? ExcelFillGradientType.Path : ExcelFillGradientType.Linear; GradientColor1 = new ExcelColorXml(nsm, topNode.SelectSingleNode(_gradientColor1Path, nsm)); GradientColor2 = new ExcelColorXml(nsm, topNode.SelectSingleNode(_gradientColor2Path, nsm)); - + GradientColor3 = new ExcelColorXml(nsm, topNode.SelectSingleNode(_gradientColor3Path, nsm)); + Top = GetXmlNodeDouble(_topPath); Bottom = GetXmlNodeDouble(_bottomPath); Left = GetXmlNodeDouble(_leftPath); @@ -43,7 +44,7 @@ internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode) : } const string _typePath = "d:gradientFill/@type"; /// - /// Type of gradient fill. + /// BulletType of gradient fill. /// public ExcelFillGradientType Type { @@ -77,6 +78,15 @@ public ExcelColorXml GradientColor2 get; private set; } + const string _gradientColor3Path = "d:gradientFill/d:stop[@position=\"0.5\"]/d:color"; + /// + /// Gradient color 2 + /// + public ExcelColorXml GradientColor3 + { + get; + private set; + } const string _bottomPath = "d:gradientFill/@bottom"; /// /// Percentage format bottom diff --git a/src/EPPlus/Style/enums/ExcelBorderStyle.cs b/src/EPPlus/Style/enums/ExcelBorderStyle.cs index 41045adab9..6e0bddf712 100644 --- a/src/EPPlus/Style/enums/ExcelBorderStyle.cs +++ b/src/EPPlus/Style/enums/ExcelBorderStyle.cs @@ -68,6 +68,10 @@ public enum ExcelBorderStyle /// /// Double line /// - Double + Double, + /// + /// Slanted Dash Dot + /// + SlantDashDot }; } \ No newline at end of file diff --git a/src/EPPlus/Style/enums/ExcelFillGradientType.cs b/src/EPPlus/Style/enums/ExcelFillGradientType.cs index 9dee9db854..ab90e2abf9 100644 --- a/src/EPPlus/Style/enums/ExcelFillGradientType.cs +++ b/src/EPPlus/Style/enums/ExcelFillGradientType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Style { /// - /// Type of gradient fill + /// BulletType of gradient fill /// public enum ExcelFillGradientType { diff --git a/src/EPPlus/Style/enums/eDxfGradientFillType.cs b/src/EPPlus/Style/enums/eDxfGradientFillType.cs index 7bbc9401ae..4ad7367224 100644 --- a/src/EPPlus/Style/enums/eDxfGradientFillType.cs +++ b/src/EPPlus/Style/enums/eDxfGradientFillType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Style { /// - /// Type of gradient fill + /// BulletType of gradient fill /// public enum eDxfGradientFillType { diff --git a/src/EPPlus/Style/enums/eStrikeType.cs b/src/EPPlus/Style/enums/eStrikeType.cs index fe78f4d785..4c7e6a9095 100644 --- a/src/EPPlus/Style/enums/eStrikeType.cs +++ b/src/EPPlus/Style/enums/eStrikeType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Style { /// - /// Type of font strike + /// BulletType of font strike /// public enum eStrikeType { diff --git a/src/EPPlus/Style/enums/eStyleClass.cs b/src/EPPlus/Style/enums/eStyleClass.cs index 5d7db5e72a..5decb7003d 100644 --- a/src/EPPlus/Style/enums/eStyleClass.cs +++ b/src/EPPlus/Style/enums/eStyleClass.cs @@ -28,6 +28,7 @@ internal enum eStyleClass FillPatternColor, FillGradientColor1, FillGradientColor2, + FillGradientColor3, NamedStyle, Style }; diff --git a/src/EPPlus/Table/ExcelTableDxfBase.cs b/src/EPPlus/Table/ExcelTableDxfBase.cs index 96c8872030..83e978a970 100644 --- a/src/EPPlus/Table/ExcelTableDxfBase.cs +++ b/src/EPPlus/Table/ExcelTableDxfBase.cs @@ -164,6 +164,9 @@ private void SetStyle(ExcelRangeBase range, eStyleClass styleClass, eStyleProper case eStyleClass.FillGradientColor2: SetStyleColor(range.Style.Fill.Gradient.Color2, styleProperty, value); break; + case eStyleClass.FillGradientColor3: + SetStyleColor(range.Style.Fill.Gradient.Color3, styleProperty, value); + break; case eStyleClass.BorderTop: SetStyleBorder(range.Style.Border.Top, styleProperty, value); break; diff --git a/src/EPPlus/Table/PivotTable/Calculation/CacheIndexItem.cs b/src/EPPlus/Table/PivotTable/Calculation/CacheIndexItem.cs index 6832e18311..081e4389b5 100644 --- a/src/EPPlus/Table/PivotTable/Calculation/CacheIndexItem.cs +++ b/src/EPPlus/Table/PivotTable/Calculation/CacheIndexItem.cs @@ -62,7 +62,7 @@ public int GetHashCode(CacheIndexItem obj) public int CompareTo(CacheIndexItem other) { - if (Key.Length != other.Key.Length) return Key.Length > other.Key.Length ? 1 : -1; //Key length should always be equal, but add handling for different key lengths as well. + if (Key.Length != other.Key.Length) return Key.Length > other.Key.Length ? 1 : -1; //Key length should always be equal, but add handling for different _key lengths as well. for (int i = 0; i < Key.Length; i++) { if (Key[i] != other.Key[i]) diff --git a/src/EPPlus/Table/PivotTable/Calculation/PivotKeyUtil.cs b/src/EPPlus/Table/PivotTable/Calculation/PivotKeyUtil.cs index f5c5af427d..6621e70ff7 100644 --- a/src/EPPlus/Table/PivotTable/Calculation/PivotKeyUtil.cs +++ b/src/EPPlus/Table/PivotTable/Calculation/PivotKeyUtil.cs @@ -31,7 +31,7 @@ internal static int[] GetKey(int size, int iv = PivotCalculationStore.SumLevelVa /// /// /// - /// Where row fields end and colfields start in the key + /// Where row fields end and colfields start in the _key /// internal static int[] GetColumnTotalKey(int[] key, int colFieldsStart) { @@ -46,7 +46,7 @@ internal static int[] GetColumnTotalKey(int[] key, int colFieldsStart) /// /// /// - /// Where row fields end and colfields start in the key + /// Where row fields end and colfields start in the _key /// internal static int[] GetRowTotalKey(int[] key, int colFieldsStart) { diff --git a/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsDifference.cs b/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsDifference.cs index 5b1630c800..d7156572de 100644 --- a/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsDifference.cs +++ b/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsDifference.cs @@ -30,7 +30,7 @@ protected void CalculateDifferenceShared(ExcelPivotTableDataField df, List var biType = df.BaseItem == (int)ePrevNextPivotItem.Previous ? -1 : (df.BaseItem == (int)ePrevNextPivotItem.Next ? 1 : 0); var maxCol = pt.Fields[df.BaseField].Items.Count - 2; var existingEmptyKeys = new HashSet(ArrayComparer.Instance); - var isLowestGroupLevel = (keyCol == colStartIx - 1 || keyCol == fieldIndex.Count - 1); //If not lowest group key set value to 1 or 0 only.; + var isLowestGroupLevel = (keyCol == colStartIx - 1 || keyCol == fieldIndex.Count - 1); //If not lowest group _key set value to 1 or 0 only.; var lastIx = fieldIndex.Count - 1; var lastItemIx = pt.Fields[fieldIndex[lastIx]].Items.Count - 1; diff --git a/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsPercentOf.cs b/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsPercentOf.cs index 57f0eff11b..30661072b9 100644 --- a/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsPercentOf.cs +++ b/src/EPPlus/Table/PivotTable/Calculation/ShowDataAs/PivotShowAsPercentOf.cs @@ -30,7 +30,7 @@ internal override void Calculate(ExcelPivotTableDataField df, List fieldInd var biType = df.BaseItem == (int)ePrevNextPivotItem.Previous ? -1 : (df.BaseItem== (int)ePrevNextPivotItem.Next ? 1 : 0); var maxCol = pt.Fields[df.BaseField].Items.Count - 2; - var isLowestGroupLevel = (keyCol == colStartIx - 1 || keyCol == fieldIndex.Count - 1); //If not lowest group key set value to 1 or 0 only.; + var isLowestGroupLevel = (keyCol == colStartIx - 1 || keyCol == fieldIndex.Count - 1); //If not lowest group _key set value to 1 or 0 only.; var currentKey = GetKey(fieldIndex.Count); var lastIx = fieldIndex.Count-1; diff --git a/src/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs b/src/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs index 443ad51efa..9453689f26 100644 --- a/src/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs +++ b/src/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs @@ -272,7 +272,7 @@ public bool SaveData } } /// - /// Type of source data + /// BulletType of source data /// public eSourceType CacheSource { diff --git a/src/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs b/src/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs index 4fd7c14b65..186b4d67a3 100644 --- a/src/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs +++ b/src/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs @@ -146,7 +146,7 @@ public string Format } } /// - /// Type of aggregate function + /// BulletType of aggregate function /// public DataFieldFunctions Function { diff --git a/src/EPPlus/Table/PivotTable/ExcelPivotTableField.cs b/src/EPPlus/Table/PivotTable/ExcelPivotTableField.cs index 37429ac83e..4a7dd347db 100644 --- a/src/EPPlus/Table/PivotTable/ExcelPivotTableField.cs +++ b/src/EPPlus/Table/PivotTable/ExcelPivotTableField.cs @@ -377,7 +377,7 @@ public eSubTotalFunctions SubTotalFunctions } } /// - /// Type of axis + /// BulletType of axis /// public ePivotFieldAxis Axis { diff --git a/src/EPPlus/Table/PivotTable/enums/ConditionType.cs b/src/EPPlus/Table/PivotTable/enums/ConditionType.cs index ea90da4848..48958f3250 100644 --- a/src/EPPlus/Table/PivotTable/enums/ConditionType.cs +++ b/src/EPPlus/Table/PivotTable/enums/ConditionType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.Table.PivotTable { /// - /// Conditional Formatting Evaluation Type + /// Conditional Formatting Evaluation BulletType /// public enum ConditionType { diff --git a/src/EPPlus/Utils/ArgumentExtensions.cs b/src/EPPlus/Utils/ArgumentExtensions.cs index 0b98f1c0b7..c796de4642 100644 --- a/src/EPPlus/Utils/ArgumentExtensions.cs +++ b/src/EPPlus/Utils/ArgumentExtensions.cs @@ -58,7 +58,7 @@ public static void IsNotNullOrEmpty(this IArgument argument, string argu /// /// Throws an ArgumentOutOfRangeException if the value of the argument is out of the supplied range /// - /// Type implementing + /// BulletType implementing /// The argument to check /// Min value of the supplied range /// Max value of the supplied range diff --git a/src/EPPlus/Utils/ColorExtensions.cs b/src/EPPlus/Utils/ColorExtensions.cs new file mode 100644 index 0000000000..7dff7f14be --- /dev/null +++ b/src/EPPlus/Utils/ColorExtensions.cs @@ -0,0 +1,13 @@ +using System.Drawing; + +namespace OfficeOpenXml.Utils +{ + internal static class ColorExtentions + { + internal static string To6CharHexString(this Color color) + { + return (color.ToArgb() & 0xFFFFFF).ToString("x6"); + } + } + +} diff --git a/src/EPPlus/Utils/CompundDocument/CompoundDocumentFile.cs b/src/EPPlus/Utils/CompundDocument/CompoundDocumentFile.cs index 9ee145de2c..bfea78a30a 100644 --- a/src/EPPlus/Utils/CompundDocument/CompoundDocumentFile.cs +++ b/src/EPPlus/Utils/CompundDocument/CompoundDocumentFile.cs @@ -774,7 +774,7 @@ private void AllocateFAT(BinaryWriter bw, int miniFatLength, List - /// Type of object + /// BulletType of object /// 0x00 - Unknown or unallocated /// 0x01 - Storage Object /// 0x02 - Stream Object diff --git a/src/EPPlus/Utils/DateUtils/DateTimeUtil.cs b/src/EPPlus/Utils/DateUtils/DateTimeUtil.cs index 26444a5e3a..7028fe1ab5 100644 --- a/src/EPPlus/Utils/DateUtils/DateTimeUtil.cs +++ b/src/EPPlus/Utils/DateUtils/DateTimeUtil.cs @@ -35,5 +35,9 @@ internal static void GetWeekDates(DateTime date, out DateTime startDate, out Dat startDate = date; endDate = date.AddDays(6); } + internal static bool IsValidOADate(double date) + { + return date >= -657435 && date < 2958466; + } } } diff --git a/src/EPPlus/Utils/EnumUtils/ExtensionFunctions.cs b/src/EPPlus/Utils/EnumUtils/ExtensionFunctions.cs index be25a24515..3c517bec3c 100644 --- a/src/EPPlus/Utils/EnumUtils/ExtensionFunctions.cs +++ b/src/EPPlus/Utils/EnumUtils/ExtensionFunctions.cs @@ -10,7 +10,9 @@ Date Author Change ************************************************************************************************* 01/27/2020 EPPlus Software AB Initial release EPPlus 5 *************************************************************************************************/ +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using System; +using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -44,6 +46,26 @@ internal static string ToEnumString(this Enum enumValue, T defaultValue) wher var s = enumValue.ToString(); return s.Substring(0, 1).ToLower() + s.Substring(1); } + /// + /// Returns the enum value with first char lower case. + /// + /// + /// + /// + /// + internal static string ToEnumString(this Enum enumValue, Dictionary lookup) where T : Enum + { + //if (enumValue.Equals(defaultValue)) + //{ + // return null; + //} + if(lookup.TryGetValue((T)enumValue, out string v)) + { + return v; + } + var s = enumValue.ToString(); + return s.Substring(0, 1).ToLower() + s.Substring(1); + } internal static T? ToEnum(this string s) where T : struct { @@ -61,6 +83,26 @@ internal static string ToEnumString(this Enum enumValue, T defaultValue) wher return null; } } + internal static T ToEnum(this string s, T defaultValue, Dictionary lookup) where T : struct + { + try + { + if (string.IsNullOrEmpty(s)) return defaultValue; + if(lookup.TryGetValue(s, out T v)) + { + return v; + } + if (!Enum.GetNames(typeof(T)).Any(x => x.Equals(s, StringComparison.OrdinalIgnoreCase))) + { + return defaultValue; + } + return (T)Enum.Parse(typeof(T), s, true); + } + catch + { + return defaultValue; + } + } internal static T ToEnum(this string s, T defaultValue) where T : struct { diff --git a/src/EPPlus/Utils/FontUtil.cs b/src/EPPlus/Utils/FontUtil.cs new file mode 100644 index 0000000000..a9fc14511c --- /dev/null +++ b/src/EPPlus/Utils/FontUtil.cs @@ -0,0 +1,69 @@ + + +using OfficeOpenXml.Interfaces.Drawing.Text; + +namespace OfficeOpenXml.Utils +{ + internal class FontUtil + { + internal static MeasurementFont GetMeasureFont(string latinFont, string complexFont, string eastAsianFont, float size, MeasurementFontStyles style, ExcelPackage pck) + { + var mf = new MeasurementFont() + { + FontFamily = string.IsNullOrEmpty(latinFont) ? complexFont : latinFont, + Size = size, + Style = style + }; + if (string.IsNullOrEmpty(mf.FontFamily)) + { + mf.FontFamily = eastAsianFont; + } + + switch (mf.FontFamily) + { + case "+mn-lt": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont.LatinFont?.Typeface; + break; + case "+mj-lt": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MajorFont.LatinFont?.Typeface; + break; + case "+mn-cs": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont.ComplexFont?.Typeface; + break; + case "+mj-cs": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MajorFont.ComplexFont?.Typeface; + break; + case "+mn-ea": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont.EastAsianFont?.Typeface; + break; + case "+mj-ea": + mf.FontFamily = pck.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MajorFont.EastAsianFont?.Typeface; + break; + } + + if (string.IsNullOrEmpty(mf.FontFamily) || mf.Size <= 0 || float.IsNaN(mf.Size)) + { + var ns = pck.Workbook.Styles.GetNormalStyle(); + if (string.IsNullOrEmpty(mf.FontFamily)) + { + if (ns == null || string.IsNullOrEmpty(ns.Style.Font.Name)) + { + mf.FontFamily = "Aptos Narrow"; + } + else + { + mf.FontFamily = ns.Style.Font.Name; + } + } + + if (mf.Size <= 0 || double.IsNaN(mf.Size)) + { + mf.Size = ns.Style.Font.Size; + } + } + + return mf; + + } + } +} diff --git a/src/EPPlus/Utils/IArgument.cs b/src/EPPlus/Utils/IArgument.cs index 6d23906ed8..0ccbf18933 100644 --- a/src/EPPlus/Utils/IArgument.cs +++ b/src/EPPlus/Utils/IArgument.cs @@ -21,7 +21,7 @@ namespace OfficeOpenXml.Utils /// /// An argument /// - /// Argument Type + /// Argument BulletType public interface IArgument { /// diff --git a/src/EPPlus/Utils/Rendering/DrawingExtensions.cs b/src/EPPlus/Utils/Rendering/DrawingExtensions.cs new file mode 100644 index 0000000000..7d93cfe143 --- /dev/null +++ b/src/EPPlus/Utils/Rendering/DrawingExtensions.cs @@ -0,0 +1,158 @@ +using EPPlus.DrawingRenderer.RenderItems; +using EPPlus.Fonts.OpenType.Utils; +using EPPlus.Graphics; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Chart; +using OfficeOpenXml.Drawing.Style.Fill; +using OfficeOpenXml.Drawing.Theme; +using OfficeOpenXml.ExternalReferences; +using System.Collections.Generic; +using System.Linq; + +namespace EPPlus.Export.Utils +{ + internal static class DrawingExtensions + { + internal static BoundingBox GetBoundingBox(this ExcelDrawing drawing) + { + return new BoundingBox() + { + Left = 0, + Top = 0, + Width = drawing.GetPixelWidth().PixelToPoint(), + Height = drawing.GetPixelHeight().PixelToPoint() + }; + } + + internal static List LoadSeriesValues(ExcelChart chart, string serieAddressInput, double[] numLiterals, string[] strLiterals) + { + string serieAddress = serieAddressInput; + + //Some addresses are split and within parenthesis + if (serieAddressInput.StartsWith("(")) + { + serieAddress = serieAddressInput.Trim('(', ')'); + } + + List values = new List(); + if (numLiterals != null) + { + values.AddRange(numLiterals.Select(x => (object)x)); + } + else if (strLiterals != null) + { + values.AddRange(strLiterals.Select(x => (object)x)); + } + else + { + if (string.IsNullOrEmpty(serieAddress)) + { + return null; + } + var address = new ExcelAddressBase(serieAddress); + + if (address.Addresses != null && address.Addresses.Count > 1) + { + foreach (var splitAddress in address.Addresses) + { + FillValuesFromAddress(chart, splitAddress, ref values); + } + } + else + { + FillValuesFromAddress(chart, address, ref values); + } + } + return values; + } + + internal static void FillValuesFromAddress(ExcelChart Chart, ExcelAddressBase address, ref List values) + { + if (address.IsExternal) + { + var wb = Chart.WorkSheet.Workbook; + var extWb = wb.ExternalLinks[address.ExternalReferenceIndex - 1] as ExcelExternalWorkbook; + if (extWb != null) + { + var wsName = address.WorkSheetName; + if (extWb.Package == null) + { + var extWs = extWb.CachedWorksheets[wsName]; + FillExternalValues(extWs, address, ref values); + } + else + { + var ws = extWb.Package.Workbook.Worksheets[wsName]; + FillInternalValues(ws, address, ref values); + } + } + } + else + { + var wsName = address.WorkSheetName; + + if (string.IsNullOrEmpty(wsName)) + { + wsName = Chart.WorkSheet.Name; + } + + var ws = Chart.WorkSheet.Workbook.Worksheets[wsName]; + FillInternalValues(ws, address, ref values); + } + } + + internal static void FillExternalValues(ExcelExternalWorksheet extWs, ExcelAddressBase address, ref List values) + { + if (extWs != null) + { + for (int r = address.Start.Row; r <= address.End.Row; r++) + { + for (int c = address.Start.Column; c <= address.End.Column; c++) + { + values.Add(extWs.CellValues[r, c].Value); + } + } + } + } + + internal static void FillInternalValues(ExcelWorksheet ws, ExcelAddressBase address, ref List values) + { + + if (ws != null) + { + for (int r = address.Start.Row; r <= address.End.Row; r++) + { + for (int c = address.Start.Column; c <= address.End.Column; c++) + { + values.Add(ws.Cells[r, c].Value); + } + } + } + } + + + internal static OffsetRectangle AsOffsetRectangle(this ExcelDrawingRectangle item) + { + return new OffsetRectangle + { + TopOffset = item.TopOffset, + BottomOffset = item.BottomOffset, + LeftOffset = item.LeftOffset, + RightOffset = item.RightOffset + }; + } + internal static FillTile AsFillTile(this ExcelDrawingBlipFillTile fillTile) + { + return new FillTile + { + Alignment = (RectangleAlignment?)fillTile.Alignment, + FlipMode = (TileFlipMode)fillTile.FlipMode, + HorizontalOffset = fillTile.HorizontalOffset, + VerticalOffset = fillTile.VerticalOffset, + HorizontalRatio = fillTile.HorizontalRatio, + VerticalRatio = fillTile.VerticalRatio + }; + } + } +} diff --git a/src/EPPlus/Utils/Rendering/MConverter.cs b/src/EPPlus/Utils/Rendering/MConverter.cs new file mode 100644 index 0000000000..ef7138a3f9 --- /dev/null +++ b/src/EPPlus/Utils/Rendering/MConverter.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OfficeOpenXml.Utils.Drawing +{ + /// + /// Math converter utils + /// + internal static class MConverter + { + internal static double DegreesToRadians(double degree) + { + return degree * (Math.Round((double)System.Math.PI, 14) / 180); + } + } +} diff --git a/src/EPPlus/Utils/String/StringExtensions.cs b/src/EPPlus/Utils/String/StringExtensions.cs index 1914c62dc8..7ec020d891 100644 --- a/src/EPPlus/Utils/String/StringExtensions.cs +++ b/src/EPPlus/Utils/String/StringExtensions.cs @@ -54,5 +54,21 @@ internal static string UnicodeSubstring(this string s, int start, int length) { return StringUtil.UnicodeSubstring(s, start, length); } + internal static string AddTrailingSlash(this string s) + { + if(string.IsNullOrEmpty(s)==false && s.EndsWith("/")==false) + { + return s + "/"; + } + return s; + } + internal static string AddPrependingSlash(this string s) + { + if (string.IsNullOrEmpty(s) == false && s.StartsWith("/") == false) + { + return "/" + s; + } + return s; + } } } diff --git a/src/EPPlus/Utils/TextUtils.cs b/src/EPPlus/Utils/TextUtils.cs new file mode 100644 index 0000000000..6cbd029bfa --- /dev/null +++ b/src/EPPlus/Utils/TextUtils.cs @@ -0,0 +1,26 @@ +using OfficeOpenXml.Drawing; +using System; + +namespace OfficeOpenXml.Utils +{ + internal static class TextUtils + { + internal static double EmuToPoint(this double emuNumber) + { + return emuNumber / ExcelDrawing.EMU_PER_POINT; + } + + + internal static double EmuToPixels(this double? emuNumber) => emuNumber.HasValue ? emuNumber.Value.EmuToPixels() : 0D; + + internal static double EmuToPixels(this double emuNumber) + { + return emuNumber / ExcelDrawing.EMU_PER_PIXEL; + } + + internal static int RoundToWhole(double number) + { + return (int)Math.Round(number, 0, MidpointRounding.AwayFromZero); + } + } +} \ No newline at end of file diff --git a/src/EPPlus/Utils/TypeConversion/ColorConverter.cs b/src/EPPlus/Utils/TypeConversion/ColorConverter.cs index aeca10c46e..7f32f6db97 100644 --- a/src/EPPlus/Utils/TypeConversion/ColorConverter.cs +++ b/src/EPPlus/Utils/TypeConversion/ColorConverter.cs @@ -10,21 +10,145 @@ Date Author Change ************************************************************************************************* 11/15/2021 EPPlus Software AB Html export *************************************************************************************************/ +using EPPlus.DrawingRenderer; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Style.Coloring; -using System.Drawing; using OfficeOpenXml.Drawing.Theme; +using System; +using System.Drawing; +using System.Linq; +using TC = OfficeOpenXml.Utils.TypeConversion; namespace OfficeOpenXml.Utils.TypeConversion { - internal class ColorConverter + public class ColorConverter { - internal static Color GetThemeColor(ExcelTheme theme, eThemeSchemeColor tc) + public static Color GetThemeColor(ExcelTheme theme, eThemeSchemeColor tc) { var cm = theme.ColorScheme.GetColorByEnum(tc); return GetThemeColor(cm); } - internal static Color GetThemeColor(ExcelDrawingThemeColorManager cm) + public static Color GetThemeColor(ExcelTheme theme, ExcelDrawingColorManager cm) + { + if(cm!=null && cm.ColorType==eDrawingColorType.Scheme) + { + var newCm=theme.ColorScheme.GetColorByEnum(cm.SchemeColor.Color); + var nc = GetThemeColor(newCm); + return ApplyTransforms(nc, cm.Transforms); + } + var c=GetThemeColor(cm); + return ApplyTransforms(c, cm.Transforms); + + } + + public static Color GetThemeColor(ExcelTheme theme, ExcelDrawingColorManager cm, ExcelDrawingColorManager cmStyle) + { + if (cm != null && cm.ColorType == eDrawingColorType.Scheme) + { + ExcelDrawingThemeColorManager newCm; + if(cm.SchemeColor.Color == eSchemeColor.Style) + { + return GetThemeColor(theme, cmStyle); + } + else + { + newCm = theme.ColorScheme.GetColorByEnum(cm.SchemeColor.Color); + } + var nc = GetThemeColor(newCm); + return ApplyTransforms(nc, cm.Transforms); + } + var c = GetThemeColor(cm); + return ApplyTransforms(c, cm.Transforms); + + } + + private static Color ApplyTransforms(Color c, ExcelColorTransformCollection transforms) + { + if (transforms==null || transforms.Count == 0) return c; + + var r = c.R; + var g = c.G; + var b = c.B; + + foreach (var t in transforms) + { + var v = t.Value / 100; + switch(t.Type) + { + case eColorTransformType.Shade: + c = ApplyTint(c, -(1-v)); + break; + case eColorTransformType.Tint: + c = ApplyTint(c, v); + break; + case eColorTransformType.HueMod: + c = ApplyHueMod(c, v); + break; + case eColorTransformType.HueOff: + c = ApplyHueMod(c, 1, v); + break; + case eColorTransformType.SatMod: + c = ApplySatMod(c, v); + break; + case eColorTransformType.SatOff: + c = ApplySatMod(c, 1, v); + break; + case eColorTransformType.LumMod: + c = ApplyLumMod(c, v); + break; + case eColorTransformType.LumOff: + c = ApplyLumMod(c, 1, v); + break; + case eColorTransformType.Alpha: + c = Color.FromArgb((byte)Math.Round(255 * v), c.R, c.G, c.B); + break; + case eColorTransformType.AlphaMod: + c = Color.FromArgb((byte)Math.Round(c.A * v), c.R, c.G, c.B); + break; + case eColorTransformType.AlphaOff: + c = Color.FromArgb((byte)(c.A + v), c.R, c.G, c.B); + break; + } + } + return c; + //return Color.FromArgb(r, g, b); + } + internal static Color ApplyHueMod(Color c, double hueMod = 1, double hueOff = 0) + { + ExcelDrawingRgbColor.GetHslColor(c, out double h, out double s, out double l); + + h = Math.Max(0, Math.Min(1, l * hueMod + hueOff)); + var ret = ExcelDrawingHslColor.GetRgb(h, s, l); + return ret; + } + + internal static Color ApplyLumMod(Color c, double lumMod=1, double lumOff=0) + { + ExcelDrawingRgbColor.GetHslColor(c, out double h, out double s, out double l); + + l = Math.Max(0, Math.Min(1, l * lumMod + lumOff)); + var ret = ExcelDrawingHslColor.GetRgb(h, s, l); + return ret; + } + internal static Color ApplySatMod(Color c, double satMod = 1, double satOff = 0) + { + var h = c.GetHue(); + var s = c.GetSaturation(); + var l = c.GetBrightness(); + + ExcelDrawingRgbColor.GetHslColor(c, out double h2, out double s2, out double l2); + + var ret1 = ExcelDrawingHslColor.GetRgb(h, s* satMod + satOff, l); + var ret2 = ExcelDrawingHslColor.GetRgb(h2, s2 * satMod + satOff, l2); + return ret2; + } + + /// + /// Converts the color to a + /// + /// The theme color manager + /// The RGB color + public static Color GetThemeColor(ExcelDrawingThemeColorManager cm) { Color color; switch (cm.ColorType) @@ -43,6 +167,7 @@ internal static Color GetThemeColor(ExcelDrawingThemeColorManager cm) color = Color.FromArgb(GetRgpPercentToRgb(rp.RedPercentage), GetRgpPercentToRgb(rp.GreenPercentage), GetRgpPercentToRgb(rp.BluePercentage)); + break; case eDrawingColorType.Hsl: color = cm.HslColor.GetRgbColor(); @@ -53,7 +178,6 @@ internal static Color GetThemeColor(ExcelDrawingThemeColorManager cm) } //TODO:Apply Transforms - return color; } @@ -68,6 +192,10 @@ internal static Color ApplyTint(Color ret, double tint) if (tint == 0) { return ret; + + + + } else { @@ -82,7 +210,60 @@ internal static Color ApplyTint(Color ret, double tint) } return ExcelDrawingHslColor.GetRgb(h, s, l); } + //if (tint < 0) + //{ + // double shade = 1+tint; + // var r = (byte)Math.Round(ret.R * shade); + // var g = (byte)Math.Round(ret.G * shade); + // var b = (byte)Math.Round(ret.B * shade); + // return Color.FromArgb(ret.A, r, g, b); + //} + //else if(tint > 0) + //{ + // double blend = 1.0 - tint; + // var r = (byte)Math.Round(ret.R + (255 - ret.R) * blend); + // var g = (byte)Math.Round(ret.G + (255 - ret.G) * blend); + // var b = (byte)Math.Round(ret.B + (255 - ret.B) * blend); + // return Color.FromArgb(ret.A, r, g, b); + //} + //return ret; + } + internal static Color ApplyBlend(Color color, Color blendColor, double percent) + { + var colorPercent = 1 - percent; + var r = (int)Math.Min(255D, color.R * colorPercent + blendColor.R * percent); + var g = (int)Math.Min(255D, color.G * colorPercent + blendColor.G * percent); + var b = (int)Math.Min(255D, color.B * colorPercent + blendColor.B * percent); + return Color.FromArgb(0xff, r, g, b); + } + internal static Color GetAdjustedColor(PathFillMode fillColorSource, Color fc) + { + switch (fillColorSource) + { + case PathFillMode.Darken: + fc = TC.ColorConverter.ApplyBlend(fc, Color.Black, 0.4); + break; + case PathFillMode.DarkenLess: + fc = TC.ColorConverter.ApplyBlend(fc, Color.Black, 50D / 255D); + break; + case PathFillMode.LightenLess: + fc = TC.ColorConverter.ApplyBlend(fc, Color.White, 50D / 255D); + break; + case PathFillMode.Lighten: + fc = TC.ColorConverter.ApplyBlend(fc, Color.White, 0.4); + break; + } + + return fc; } + internal static double GetOpacity(ExcelDrawingColorManager color) + { + if(color.Transforms.Where(t=>t.Type==eColorTransformType.Alpha).FirstOrDefault() is IColorTransformItem alpha) + { + return alpha.Value / 100; + } + return 1D; + } } } diff --git a/src/EPPlus/Utils/TypeConversion/ConvertUtil.cs b/src/EPPlus/Utils/TypeConversion/ConvertUtil.cs index a582adf09c..2687999062 100644 --- a/src/EPPlus/Utils/TypeConversion/ConvertUtil.cs +++ b/src/EPPlus/Utils/TypeConversion/ConvertUtil.cs @@ -195,7 +195,16 @@ internal static bool TryParseIntString(string candidateString, out int result) result = 0; return false; } - + internal static int? GetValueIntNull(string s) + { + if (string.IsNullOrEmpty(s)) return null; + return int.Parse(s, CultureInfo.InvariantCulture); + } + internal static long? GetValueLongNull(string s) + { + if (string.IsNullOrEmpty(s)) return null; + return long.Parse(s, CultureInfo.InvariantCulture); + } /// /// Tries to parse a from the specified which is expected to be a string value. /// diff --git a/src/EPPlus/Vba/ContentHash/V3NormalizedDataHashInputProvider.cs b/src/EPPlus/Vba/ContentHash/V3NormalizedDataHashInputProvider.cs index 96dde07c15..f729229bbb 100644 --- a/src/EPPlus/Vba/ContentHash/V3NormalizedDataHashInputProvider.cs +++ b/src/EPPlus/Vba/ContentHash/V3NormalizedDataHashInputProvider.cs @@ -65,7 +65,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTSYSKIND.Id (section 2.3.4.2.1.1) of Storage bw.Write((ushort)0x0001); - // APPEND Buffer WITH PROJECTSYSKIND.Size (section 2.3.4.2.1.1) of Storage + // APPEND Buffer WITH PROJECTSYSKIND.FontSize (section 2.3.4.2.1.1) of Storage bw.Write((uint)0x00000004); /****************************************** @@ -76,7 +76,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) bw.Write((ushort)0x0002); - // APPEND Buffer WITH PROJECTLCID.Size (section 2.3.4.2.1.3) of Storage + // APPEND Buffer WITH PROJECTLCID.FontSize (section 2.3.4.2.1.3) of Storage bw.Write((uint)0x00000004); // APPEND Buffer WITH PROJECTLCID.Lcid (section 2.3.4.2.1.3) of Storage @@ -89,7 +89,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTLCIDINVOKE.Id (section 2.3.4.2.1.4) of Storage bw.Write((ushort)0x0014); - // APPEND Buffer WITH PROJECTLCIDINVOKE.Size (section 2.3.4.2.1.4) of Storage + // APPEND Buffer WITH PROJECTLCIDINVOKE.FontSize (section 2.3.4.2.1.4) of Storage bw.Write((uint)0x00000004); // APPEND Buffer WITH PROJECTLCIDINVOKE.LcidInvoke (section 2.3.4.2.1.4) of Storage @@ -102,7 +102,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTCODEPAGE.Id (section 2.3.4.2.1.5) of Storage bw.Write((ushort)0x0003); - // APPEND Buffer WITH PROJECTCODEPAGE.Size (section 2.3.4.2.1.5) of Storage + // APPEND Buffer WITH PROJECTCODEPAGE.FontSize (section 2.3.4.2.1.5) of Storage bw.Write((uint)0x00000002); /****************************************** @@ -163,7 +163,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTHELPCONTEXT.Id (section 2.3.4.2.1.9) of Storage bw.Write((ushort)0x0007); - // APPEND Buffer WITH PROJECTHELPCONTEXT.Size (section 2.3.4.2.1.9) of Storage + // APPEND Buffer WITH PROJECTHELPCONTEXT.FontSize (section 2.3.4.2.1.9) of Storage bw.Write((uint)0x00000004); /****************************************** @@ -173,7 +173,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTLIBFLAGS.Id (section 2.3.4.2.1.10) of Storage bw.Write((ushort)0x0008); - // APPEND Buffer WITH PROJECTLIBFLAGS.Size (section 2.3.4.2.1.10) of Storage + // APPEND Buffer WITH PROJECTLIBFLAGS.FontSize (section 2.3.4.2.1.10) of Storage bw.Write((uint)0x00000004); // APPEND Buffer WITH PROJECTLIBFLAGS.ProjectLibFlags (section 2.3.4.2.1.10) of Storage @@ -240,8 +240,8 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTMODULES.Id (section 2.3.4.2.3) of Storage bw.Write((ushort)0x000F); - // APPEND Buffer WITH PROJECTMODULES.Size (section 2.3.4.2.3) of Storage - bw.Write((uint)0x00000002); // Size + // APPEND Buffer WITH PROJECTMODULES.FontSize (section 2.3.4.2.3) of Storage + bw.Write((uint)0x00000002); // FontSize /****************************************** * 2.3.4.2.3.1 PROJECTCOOKIE Record * @@ -250,7 +250,7 @@ private void CreateV3NormalizedDataHashInput(BinaryWriter bw) // APPEND Buffer WITH PROJECTCOOKIE.Id (section 2.3.4.2.3.1) of Storage bw.Write((ushort)0x0013); - // APPEND Buffer WITH PROJECTCOOKIE.Size (section 2.3.4.2.3.1) of Storage + // APPEND Buffer WITH PROJECTCOOKIE.FontSize (section 2.3.4.2.3.1) of Storage bw.Write((uint)0x00000002); /* @@ -418,7 +418,7 @@ private static void WriteNameRecord(BinaryWriter bw, ExcelVbaReference reference var refNameBytes = encoding.GetBytes(reference.Name); // APPEND Buffer WITH REFERENCENAME.SizeOfName (section 2.3.4.2.2.2) - bw.Write((uint)refNameBytes.Length); // Size + bw.Write((uint)refNameBytes.Length); // FontSize // APPEND Buffer WITH REFERENCENAME.Name(section 2.3.4.2.2.2) bw.Write(refNameBytes); // Name diff --git a/src/EPPlus/Vba/ExcelVBAProject.cs b/src/EPPlus/Vba/ExcelVBAProject.cs index 23f7163667..d06c803d87 100644 --- a/src/EPPlus/Vba/ExcelVBAProject.cs +++ b/src/EPPlus/Vba/ExcelVBAProject.cs @@ -709,62 +709,62 @@ private byte[] CreateDirStream() /****** PROJECTINFORMATION Record ******/ bw.Write((ushort)1); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)SystemKind); //SysKind if(CompatVersion.HasValue) { bw.Write((ushort)0x4a); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)CompatVersion.Value); //compatversion } bw.Write((ushort)2); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)Lcid); //Lcid bw.Write((ushort)0x14); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)LcidInvoke); //Lcid Invoke bw.Write((ushort)3); //ID - bw.Write((uint)2); //Size + bw.Write((uint)2); //FontSize bw.Write((ushort)CodePage); //Codepage //ProjectName bw.Write((ushort)4); //ID var nameBytes = Encoding.GetEncoding(CodePage).GetBytes(Name); - bw.Write((uint)nameBytes.Length); //Size + bw.Write((uint)nameBytes.Length); //FontSize bw.Write(nameBytes); //Project Name //Description bw.Write((ushort)5); //ID var descriptionBytes = Encoding.GetEncoding(CodePage).GetBytes(Description); - bw.Write((uint)descriptionBytes.Length); //Size + bw.Write((uint)descriptionBytes.Length); //FontSize bw.Write(descriptionBytes); //Project Name bw.Write((ushort)0x40); //ID var descriptionUnicodeBytes = Encoding.Unicode.GetBytes(Description); - bw.Write((uint)descriptionUnicodeBytes.Length); //Size + bw.Write((uint)descriptionUnicodeBytes.Length); //FontSize bw.Write(descriptionUnicodeBytes); //Project Description //Helpfiles bw.Write((ushort)6); //ID var helpFile1Bytes = Encoding.GetEncoding(CodePage).GetBytes(HelpFile1); - bw.Write((uint)helpFile1Bytes.Length); //Size + bw.Write((uint)helpFile1Bytes.Length); //FontSize bw.Write(helpFile1Bytes); //HelpFile1 bw.Write((ushort)0x3D); //ID var helpFile2Bytes = Encoding.GetEncoding(CodePage).GetBytes(HelpFile2); - bw.Write((uint)helpFile2Bytes.Length); //Size + bw.Write((uint)helpFile2Bytes.Length); //FontSize bw.Write(helpFile2Bytes); //HelpFile2 //Help context id bw.Write((ushort)7); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)HelpContextID); //Help context id //Libflags bw.Write((ushort)8); //ID - bw.Write((uint)4); //Size + bw.Write((uint)4); //FontSize bw.Write((uint)0); //Help context id //Vba Version @@ -777,12 +777,12 @@ private byte[] CreateDirStream() bw.Write((ushort)0x0C); //ID var constantsBytes = Encoding.GetEncoding(CodePage).GetBytes(Constants); - bw.Write((uint)constantsBytes.Length); //Size + bw.Write((uint)constantsBytes.Length); //FontSize bw.Write(constantsBytes); var constantsUnicodeBytes = Encoding.Unicode.GetBytes(Constants); bw.Write((ushort)0x3C); //ID - bw.Write((uint)constantsUnicodeBytes.Length); //Size + bw.Write((uint)constantsUnicodeBytes.Length); //FontSize bw.Write(constantsUnicodeBytes); // /****** PROJECTREFERENCES Record ******/ @@ -893,13 +893,13 @@ private void WriteNameReference(BinaryWriter bw, ExcelVbaReference reference) //Name record bw.Write((ushort)0x16); //ID var nameBytes = Encoding.GetEncoding(CodePage).GetBytes(reference.Name); - bw.Write((uint)nameBytes.Length); //Size + bw.Write((uint)nameBytes.Length); //FontSize bw.Write(nameBytes); //HelpFile1 bw.Write((ushort)0x3E); //ID var nameUnicodeBytes = Encoding.Unicode.GetBytes(reference.Name); - bw.Write((uint)nameUnicodeBytes.Length); //Size + bw.Write((uint)nameUnicodeBytes.Length); //FontSize bw.Write(nameUnicodeBytes); //HelpFile2 } private void WriteControlReference(BinaryWriter bw, ExcelVbaReference reference) @@ -910,8 +910,8 @@ private void WriteControlReference(BinaryWriter bw, ExcelVbaReference reference) var controlRef=(ExcelVbaReferenceControl)reference; var libIdTwiddledBytes = Encoding.GetEncoding(CodePage).GetBytes(controlRef.LibIdTwiddled); - bw.Write((uint)(4 + libIdTwiddledBytes.Length + 4 + 2)); // Size of SizeOfLibidTwiddled, LibidTwiddled, Reserved1, and Reserved2. - bw.Write((uint)libIdTwiddledBytes.Length); //Size + bw.Write((uint)(4 + libIdTwiddledBytes.Length + 4 + 2)); // FontSize of SizeOfLibidTwiddled, LibidTwiddled, Reserved1, and Reserved2. + bw.Write((uint)libIdTwiddledBytes.Length); //FontSize bw.Write(libIdTwiddledBytes); //LibID bw.Write((uint)0); //Reserved1 @@ -920,8 +920,8 @@ private void WriteControlReference(BinaryWriter bw, ExcelVbaReference reference) bw.Write((ushort)0x30); //Reserved3 var libIdExternalBytes = Encoding.GetEncoding(CodePage).GetBytes(controlRef.LibIdExtended); - bw.Write((uint)(4 + libIdExternalBytes.Length + 4 + 2 + 16 + 4)); //Size of SizeOfLibidExtended, LibidExtended, Reserved4, Reserved5, OriginalTypeLib, and Cookie - bw.Write((uint)libIdExternalBytes.Length); //Size + bw.Write((uint)(4 + libIdExternalBytes.Length + 4 + 2 + 16 + 4)); //FontSize of SizeOfLibidExtended, LibidExtended, Reserved4, Reserved5, OriginalTypeLib, and Cookie + bw.Write((uint)libIdExternalBytes.Length); //FontSize bw.Write(libIdExternalBytes); //LibID bw.Write((uint)0); //Reserved4 bw.Write((ushort)0); //Reserved5 diff --git a/src/EPPlus/Vba/ExcelVBASignature.cs b/src/EPPlus/Vba/ExcelVBASignature.cs index 653e6c60c0..0cf321dd01 100644 --- a/src/EPPlus/Vba/ExcelVBASignature.cs +++ b/src/EPPlus/Vba/ExcelVBASignature.cs @@ -46,7 +46,7 @@ internal ExcelVbaSignature(Packaging.ZipPackagePart vbaPart) /// /// The certificate to sign the VBA project. /// - /// This certificate must have a private key. + /// This certificate must have a private _key. /// There is no validation that the certificate is valid for codesigning, so make sure it's valid to sign Excel files (Excel 2010 is more strict that prior versions). /// /// diff --git a/src/EPPlus/Vba/ExcelVbaModule.cs b/src/EPPlus/Vba/ExcelVbaModule.cs index 96b015efa3..55043c5979 100644 --- a/src/EPPlus/Vba/ExcelVbaModule.cs +++ b/src/EPPlus/Vba/ExcelVbaModule.cs @@ -118,7 +118,7 @@ public string Code { /// public ExcelVbaModuleAttributesCollection Attributes { get; internal set; } /// - /// Type of module + /// BulletType of module /// public eModuleType Type { get; internal set; } /// diff --git a/src/EPPlus/Vba/ExcelVbaProtection.cs b/src/EPPlus/Vba/ExcelVbaProtection.cs index 3b4596c05e..eb0bfd0551 100644 --- a/src/EPPlus/Vba/ExcelVbaProtection.cs +++ b/src/EPPlus/Vba/ExcelVbaProtection.cs @@ -69,7 +69,7 @@ public void SetPassword(string Password) { //Join Password and Key byte[] data; - //Set the key + //Set the _key PasswordKey = new byte[4]; RandomNumberGenerator r = RandomNumberGenerator.Create(); r.GetBytes(PasswordKey); diff --git a/src/EPPlus/Vba/Signatures/ProjectSignUtil.cs b/src/EPPlus/Vba/Signatures/ProjectSignUtil.cs index 9544f29f7f..0fc9356979 100644 --- a/src/EPPlus/Vba/Signatures/ProjectSignUtil.cs +++ b/src/EPPlus/Vba/Signatures/ProjectSignUtil.cs @@ -53,7 +53,7 @@ private static ContentInfo CreateContentInfo(byte[] hash, MemoryStream ms, EPPlu var hashAlgorithmBytes = ctx.GetHashAlgorithmBytes(); var hashContentBytes = GetHashContent(ctx, hash); - bw.Write((byte)0x30); //Constructed Type + bw.Write((byte)0x30); //Constructed BulletType if (ctx.SignatureType == ExcelVbaSignatureType.Legacy) { bw.Write((byte)(hashAlgorithmBytes.Length + hashContentBytes.Length + 0x18)); //Total length @@ -63,7 +63,7 @@ private static ContentInfo CreateContentInfo(byte[] hash, MemoryStream ms, EPPlu var length = (byte)(hashAlgorithmBytes.Length + hashContentBytes.Length + 0x24); WriteSequenceLength(bw, length); } - bw.Write((byte)0x30); //Constructed Type + bw.Write((byte)0x30); //Constructed BulletType bw.Write((byte)0x0E); //Length SpcIndirectDataContent var spcIndirectDataContentOidBytes = ctx.GetIndirectDataContentOidBytes(); @@ -77,14 +77,14 @@ private static ContentInfo CreateContentInfo(byte[] hash, MemoryStream ms, EPPlu { // SigFormatDescriptorV1 bw.Write((byte)0x04); - bw.Write((byte)0x0C); // Size of octstring + bw.Write((byte)0x0C); // FontSize of octstring bw.Write(12); // size of record bw.Write(1); // version bw.Write(1);// format } - bw.Write((byte)0x30); //Constructed Type (DigestInfo) + bw.Write((byte)0x30); //Constructed BulletType (DigestInfo) bw.Write((byte)(hashAlgorithmBytes.Length + 6)); //Length DigestInfo - bw.Write((byte)0x30); //Constructed Type (Algorithm) + bw.Write((byte)0x30); //Constructed BulletType (Algorithm) bw.Write((byte)(hashAlgorithmBytes.Length + 2)); //length AlgorithmIdentifier WriteOid(bw, hashAlgorithmBytes); //Hash Algorithm diff --git a/src/EPPlus/Vba/Signatures/SignatureReader.cs b/src/EPPlus/Vba/Signatures/SignatureReader.cs index 2fdc382981..7ad5e3c365 100644 --- a/src/EPPlus/Vba/Signatures/SignatureReader.cs +++ b/src/EPPlus/Vba/Signatures/SignatureReader.cs @@ -146,12 +146,10 @@ private static int ReadSequence(BinaryReader br) } else if(lengthBytes.Length == 2) { - //Array.Reverse(lengthBytes); return BitConverter.ToInt16(lengthBytes.AsEnumerable().Reverse().ToArray(), 0); } else { - Array.Reverse(lengthBytes); return BitConverter.ToInt32(lengthBytes.AsEnumerable().Reverse().ToArray(), 0); } } diff --git a/src/EPPlus/Vba/enums/eModuleType.cs b/src/EPPlus/Vba/enums/eModuleType.cs index 52eeaa50c5..26c64283cf 100644 --- a/src/EPPlus/Vba/enums/eModuleType.cs +++ b/src/EPPlus/Vba/enums/eModuleType.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.VBA { /// - /// Type of VBA module + /// BulletType of VBA module /// public enum eModuleType { diff --git a/src/EPPlus/Vba/enums/eSyskind.cs b/src/EPPlus/Vba/enums/eSyskind.cs index e13dd064f0..fcf4c1b790 100644 --- a/src/EPPlus/Vba/enums/eSyskind.cs +++ b/src/EPPlus/Vba/enums/eSyskind.cs @@ -13,7 +13,7 @@ Date Author Change namespace OfficeOpenXml.VBA { /// - /// Type of system where the VBA project was created. + /// BulletType of system where the VBA project was created. /// public enum eSyskind { diff --git a/src/EPPlus/XmlHelper.cs b/src/EPPlus/XmlHelper.cs index 74584a47e1..5bd7666bf3 100644 --- a/src/EPPlus/XmlHelper.cs +++ b/src/EPPlus/XmlHelper.cs @@ -24,6 +24,7 @@ Date Author Change using OfficeOpenXml.Packaging.Ionic.Zip; using OfficeOpenXml.Utils.TypeConversion; using OfficeOpenXml.Utils.EnumUtils; +using OfficeOpenXml.Drawing; using System.Xml.XPath; namespace OfficeOpenXml @@ -658,6 +659,7 @@ private XmlNode GetPrependNode(string nodeName, XmlNode node, ref int index) XmlNode prependNode = null; foreach (XmlNode childNode in node.ChildNodes) { + if (childNode.NodeType != XmlNodeType.Element) continue; string checkNodeName; if (childNode.LocalName == "AlternateContent") //AlternateContent contains the node that should be in the correnct order. For example AlternateContent/Choice/controls { @@ -1146,19 +1148,25 @@ internal double GetXmlNodeEmuToPt(string path) { var v = GetXmlNodeLong(path); if (v < 0) return 0; - return (double)(v / (double)Drawing.ExcelDrawing.EMU_PER_POINT); + return (double)(v / (double)ExcelDrawing.EMU_PER_POINT); } - internal double GetXmlNodeEmuToPixel(string path) + internal double GetXmlNodeEmuToPixel(string path, double defaultValue=0) { var v = GetXmlNodeLong(path); - if (v < 0) return 0; - return (double)(v / (double)Drawing.ExcelDrawing.EMU_PER_PIXEL); + if (v < 0) return defaultValue; + return (double)(v / (double)ExcelDrawing.EMU_PER_PIXEL); + } + internal double? GetXmlNodeEmuToPixelNull(string path) + { + var v = GetXmlNodeLongNull(path); + if (v == null) return null; + return (double)(v / (double)ExcelDrawing.EMU_PER_PIXEL); } internal double? GetXmlNodeEmuToPtNull(string path) { var v = GetXmlNodeLongNull(path); if (v == null) return null; - return (double)(v / (double)Drawing.ExcelDrawing.EMU_PER_POINT); + return (double)(v / (double)ExcelDrawing.EMU_PER_POINT); } internal int? GetXmlNodeIntNull(string path) { @@ -1245,12 +1253,18 @@ internal decimal GetXmlNodeDecimal(string path) } } } - internal double GetXmlNodeDouble(string path) + /// + /// Returns the xml value as double + /// + /// xpath + /// The value returned if the path does not exist. + /// The double. If the value is not a double, double.NaN is returned. + internal double GetXmlNodeDouble(string path, double defaultValue = double.NaN) { string s = GetXmlNodeString(path); if (s == "") { - return double.NaN; + return defaultValue; } else { @@ -1352,7 +1366,11 @@ internal T GetXmlEnum(string path, T defaultValue) where T : struct, Enum return v.ToEnum(default(T)); } } - + /// + /// ST_Percentage and various undertypes is read in as double in range 0-100 + /// + /// + /// internal double? GetXmlNodePercentage(string path) { double d; @@ -1609,5 +1627,26 @@ internal static int GetRichTextPropertyInt(XmlNode n) } return 0; } + /// + /// Returns a percent value from a richtext node. If the value ends with a "%", the value is returned * 100 + /// + /// + /// + internal static double GetRichTextPropertyDouble(XmlNode n) + { + if (n != null) + { + var v = n.Attributes["val"].Value; + if(v.EndsWith("%")) + { + return double.Parse(v.Substring(0, v.Length - 1)) * 100; // return in EMU + } + else + { + return double.Parse(v); // return in EMU + } + } + return 0; + } } } diff --git a/src/EPPlusTest/CompoundDocTests.cs b/src/EPPlusTest/CompoundDocTests.cs index 03a8fef16b..0fe07c96c3 100644 --- a/src/EPPlusTest/CompoundDocTests.cs +++ b/src/EPPlusTest/CompoundDocTests.cs @@ -74,7 +74,7 @@ public void Read() private void printitems(CompoundDocumentItem item) { - File.AppendAllText(@"c:\temp\items.txt", item.Name+ "\t"); + File.AppendAllText(@"c:\temp\_items.txt", item.Name+ "\t"); foreach(var c in item.Children) { printitems(c); diff --git a/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs index 104fc350ba..7ad15d3a31 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs @@ -269,7 +269,7 @@ public void CF_ColorScaleAddressChange() cfRule1.Style.Font.Bold = true; // But others you can't (readonly) - // cfRule1.Type = eExcelConditionalFormattingRuleType.ThreeColorScale; + // cfRule1.BulletType = eExcelConditionalFormattingRuleType.ThreeColorScale; // ------------------------------------------------------------------- // ThreeColorScale Conditional Formatting example diff --git a/src/EPPlusTest/ConfigureFontsTests.cs b/src/EPPlusTest/ConfigureFontsTests.cs new file mode 100644 index 0000000000..dc9f86f7e1 --- /dev/null +++ b/src/EPPlusTest/ConfigureFontsTests.cs @@ -0,0 +1,147 @@ +using EPPlus.Fonts.OpenType; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml; +using OfficeOpenXml.Interfaces.Fonts; +using System; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace EPPlusTest +{ + [TestClass] + public class ConfigureFontsTests : FontTestBase + { + private static string RenderTextbox(ExcelWorksheet sheet, string text, string fontName) + { + var tb = sheet.Drawings.AddTextbox("txtBox1"); + tb.Text = text; + tb.Font.LatinFont = fontName; + return tb.ToSvg(); + } + + private static string RenderTextbox(ExcelPackage package, string text, string fontName) + { + var sheet = package.Workbook.Worksheets.Add("Sheet1"); + return RenderTextbox(sheet, text, fontName); + } + + private static string RenderRobotoTextbox(ExcelPackage package) + { + return RenderTextbox(package, "Hello", "Roboto"); + } + + // Pulls the first tspan baseline y out of the SVG. It's computed from the resolved font's + // ascent, so it differs between fonts — unlike font-size, which is just the requested size. + private static double GetFirstTspanBaselineY(string svg) + { + var m = Regex.Match(svg, @"]*\by\s*=""([0-9.]+)px"""); + Assert.IsTrue(m.Success, "Expected a tspan with a y position in the SVG."); + return double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture); + } + + [TestMethod] + public void ConfigureFonts_Null_ThrowsArgumentNullException() + { + using var package = new ExcelPackage(); + Assert.ThrowsExactly( + () => package.Workbook.ConfigureFonts(null)); + } + + [TestMethod] + public void ConfigureFonts_ConfiguredDirectory_ResolvesRoboto() + { + using var package = new ExcelPackage(); + package.Workbook.ConfigureFonts(cfg => + { + cfg.FontDirectories.Add(FontFolder); + cfg.SearchSystemDirectories = false; + }); + + var svg = RenderRobotoTextbox(package); + + // The requested name always appears; the real proof is that rendering with the + // directory configured does not throw and produces a measurable tspan. + StringAssert.Contains(svg, "font-family=\"Roboto"); + Assert.IsTrue(GetFirstTspanBaselineY(svg) > 0); + } + + [TestMethod] + public void ConfigureFonts_IsPerWorkbook() + { + // Workbook A: Roboto directory available, system search off → resolves Roboto. + using var packageA = new ExcelPackage(); + packageA.Workbook.ConfigureFonts(cfg => + { + cfg.FontDirectories.Add(FontFolder); + cfg.SearchSystemDirectories = false; + }); + + // Workbook B: no Roboto directory, system search off → falls back to the + // embedded Archivo Narrow, which has different metrics than Roboto. + using var packageB = new ExcelPackage(); + packageB.Workbook.ConfigureFonts(cfg => + { + cfg.SearchSystemDirectories = false; + }); + + var svgA = RenderRobotoTextbox(packageA); + var svgB = RenderRobotoTextbox(packageB); + + var baselineA = GetFirstTspanBaselineY(svgA); + var baselineB = GetFirstTspanBaselineY(svgB); + + // Different resolved fonts → different measured size. This proves the configuration + // affected resolution per workbook, not just that the requested name was echoed. + Assert.AreNotEqual(baselineA, baselineB, + "Workbook A (Roboto) and workbook B (embedded fallback) must measure differently, proving per-workbook font resolution."); + } + + [TestMethod] + public void ConfigureFonts_FontFallbacks_AreApplied() + { + // A: maps a non-existent font name to Roboto via the user fallback chain. + using var packageA = new ExcelPackage(); + packageA.Workbook.ConfigureFonts(cfg => + { + cfg.FontDirectories.Add(FontFolder); + cfg.SearchSystemDirectories = false; + cfg.FontFallbacks["NoSuchFont"] = new[] { "Roboto" }; + }); + + // B: same missing font, no fallback chain → resolves via built-in chain to embedded. + using var packageB = new ExcelPackage(); + packageB.Workbook.ConfigureFonts(cfg => + { + cfg.FontDirectories.Add(FontFolder); + cfg.SearchSystemDirectories = false; + }); + + var baselineA = GetFirstTspanBaselineY(RenderTextbox(packageA, "Hello", "NoSuchFont")); + var baselineB = GetFirstTspanBaselineY(RenderTextbox(packageB, "Hello", "NoSuchFont")); + + Assert.AreNotEqual(baselineA, baselineB, + "The user fallback chain should route the missing font to Roboto, measuring differently than the built-in fallback."); + } + + [TestMethod] + public void SetScriptFallback_RoutesHanGlyphsToConfiguredFont() + { + var engine = new OpenTypeFontEngine(cfg => + { + cfg.FontDirectories.Add(FontFolder); + cfg.SearchSystemDirectories = false; + cfg.SetScriptFallback(UnicodeScript.Han, "BIZ UDGothic"); + }); + + var shaper = engine.GetTextShaper("Open Sans"); // Latin-only primary + var result = shaper.Shape("日本語"); + var usedFonts = shaper.GetUsedFonts().ToList(); + + // The Han glyphs could not come from Open Sans; they must have been routed + // to the configured BIZ UDGothic via the script fallback. + Assert.IsTrue(usedFonts.Any(f => f.FullName.Contains("BIZ UDGothic") || f.FullName.Contains("BIZUDGothic")), + "Han glyphs should be routed to the configured script-fallback font."); + } + } +} \ No newline at end of file diff --git a/src/EPPlusTest/Core/ExternalReferenceTest.cs b/src/EPPlusTest/Core/ExternalReferenceTest.cs index 915079986f..47a8e8ff75 100644 --- a/src/EPPlusTest/Core/ExternalReferenceTest.cs +++ b/src/EPPlusTest/Core/ExternalReferenceTest.cs @@ -4,6 +4,7 @@ using OfficeOpenXml.ExternalReferences; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using System.Collections.Generic; +using System.Diagnostics.Eventing.Reader; using System.IO; namespace EPPlusTest.Core @@ -327,7 +328,6 @@ public void AddExternalLinkShouldBeSameAsExcel() ws1.Cells["G3"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet1'!$C3"; ws1.Cells["G4"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet8888'!$C3"; var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx")); - ws1.Cells["G5"].Formula = $"[{er.Index}]Sheet1!FromF2*[{er.Index}]!CellH5"; er.UpdateCache(); @@ -357,6 +357,7 @@ public void AddExternalWorkbookNoUpdate() ws1.Cells["F3"].Formula = "Table1[[#This Row],[b]]+[1]Sheet1!$B3"; ws1.Cells["G3"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet1'!$C3"; var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx")); + er.IsPathRelative = false; ws1.Cells["G5"].Formula = $"[{er.Index}]Sheet1!FromF2*[{er.Index}]!CellH5"; ws1.Cells["G6"].Formula = $"'[FromWB1.xlsx]Sheet1'!FromF2*[FromWB1.xlsx]Sheet1!H6"; @@ -455,8 +456,10 @@ public void ReferencingWorkbookTest() { var ws = package.Workbook.Worksheets[0]; - package.Workbook.ExternalLinks[0].As.ExternalWorkbook.Load(); - + var ewb = package.Workbook.ExternalLinks[0].As.ExternalWorkbook; + ewb.IsPathRelative = false; + ewb.Load(); + var f1 = ws.Cells["A1"].Formula; var f2 = ws.Cells["B2"].Formula; var f3 = ws.Cells["C3"].Formula; diff --git a/src/EPPlusTest/Core/QuadTreeTest.cs b/src/EPPlusTest/Core/QuadTreeTest.cs index 3292dc89e9..ae5a46ae4a 100644 --- a/src/EPPlusTest/Core/QuadTreeTest.cs +++ b/src/EPPlusTest/Core/QuadTreeTest.cs @@ -72,7 +72,7 @@ public void QuadLargeTest() sw.Start(); var items = AddRangeItems(rows, cols, qt, 50, 50); sw.Stop(); - Debug.WriteLine($"Added {items} items in {sw.ElapsedMilliseconds} ms"); + Debug.WriteLine($"Added {items} _items in {sw.ElapsedMilliseconds} ms"); sw.Restart(); var r1 = new QuadRange(5000, 200, 10000, 300); @@ -85,7 +85,7 @@ public void QuadLargeTest() } } sw.Stop(); - Debug.WriteLine($"Queried {ir1.Count} items in {sw.ElapsedMilliseconds} ms"); + Debug.WriteLine($"Queried {ir1.Count} _items in {sw.ElapsedMilliseconds} ms"); } [TestMethod] public void QuadTree_InsertRows_Inside() diff --git a/src/EPPlusTest/Core/SharedFormulasTest.cs b/src/EPPlusTest/Core/SharedFormulasTest.cs index 501e30a0a3..474df34f35 100644 --- a/src/EPPlusTest/Core/SharedFormulasTest.cs +++ b/src/EPPlusTest/Core/SharedFormulasTest.cs @@ -17,6 +17,7 @@ public static void Init(TestContext context) public static void Cleanup() { } + [TestMethod] public void SharedFormulasShouldNotEffectFullColumn() { diff --git a/src/EPPlusTest/Core/Worksheet/AutofitWithSerializedFontMetricsTests.cs b/src/EPPlusTest/Core/Worksheet/AutofitWithSerializedFontMetricsTests.cs index 448d57d1f0..7e388c0deb 100644 --- a/src/EPPlusTest/Core/Worksheet/AutofitWithSerializedFontMetricsTests.cs +++ b/src/EPPlusTest/Core/Worksheet/AutofitWithSerializedFontMetricsTests.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; namespace EPPlusTest.Core.Worksheet { diff --git a/src/EPPlusTest/Drawing/BorderTest.cs b/src/EPPlusTest/Drawing/BorderTest.cs index 6dca521cde..600f4975fc 100644 --- a/src/EPPlusTest/Drawing/BorderTest.cs +++ b/src/EPPlusTest/Drawing/BorderTest.cs @@ -84,14 +84,14 @@ public void BorderWidthStyle() shape.Border.Fill.Color = Color.Red; shape.Border.Width = 12; shape.Border.LineStyle = eLineStyle.Dot; - shape.Border.CompoundLineStyle = eCompundLineStyle.TripleThinThickThin; + shape.Border.CompoundLineStyle = eCompoundLineStyle.TripleThinThickThin; //Assert Assert.AreEqual(eFillStyle.SolidFill, shape.Border.Fill.Style); Assert.IsNotNull(shape.Border.Fill.SolidFill); Assert.AreEqual(12, shape.Border.Width); Assert.AreEqual(eLineStyle.Dot, shape.Border.LineStyle); - Assert.AreEqual(eCompundLineStyle.TripleThinThickThin, shape.Border.CompoundLineStyle); + Assert.AreEqual(eCompoundLineStyle.TripleThinThickThin, shape.Border.CompoundLineStyle); } [TestMethod] public void BorderAlignRoundJoin() @@ -105,7 +105,7 @@ public void BorderAlignRoundJoin() //Act shape.Border.Fill.Color = Color.Red; shape.Border.LineStyle = eLineStyle.LongDashDotDot; - shape.Border.CompoundLineStyle = eCompundLineStyle.Double; + shape.Border.CompoundLineStyle = eCompoundLineStyle.Double; shape.Border.Alignment = ePenAlignment.Inset; shape.Border.LineCap = eLineCap.Square; shape.Border.Join = eLineJoin.Round; @@ -114,7 +114,7 @@ public void BorderAlignRoundJoin() Assert.AreEqual(eFillStyle.SolidFill, shape.Border.Fill.Style); Assert.IsNotNull(shape.Border.Fill.SolidFill); Assert.AreEqual(eLineStyle.LongDashDotDot, shape.Border.LineStyle); - Assert.AreEqual(eCompundLineStyle.Double, shape.Border.CompoundLineStyle); + Assert.AreEqual(eCompoundLineStyle.Double, shape.Border.CompoundLineStyle); Assert.AreEqual(ePenAlignment.Inset, shape.Border.Alignment); Assert.AreEqual(eLineJoin.Round, shape.Border.Join); Assert.AreEqual(eLineCap.Square, shape.Border.LineCap); @@ -131,7 +131,7 @@ public void BorderMitterJoin() //Act shape.Border.Fill.Color = Color.Red; shape.Border.LineStyle = eLineStyle.LongDashDotDot; - shape.Border.CompoundLineStyle = eCompundLineStyle.Double; + shape.Border.CompoundLineStyle = eCompoundLineStyle.Double; shape.Border.LineCap = eLineCap.Flat; shape.Border.Join = eLineJoin.Bevel; shape.Border.MiterJoinLimit=10000; //Sets join to Miter @@ -140,7 +140,7 @@ public void BorderMitterJoin() Assert.AreEqual(eFillStyle.SolidFill, shape.Border.Fill.Style); Assert.IsNotNull(shape.Border.Fill.SolidFill); Assert.AreEqual(eLineStyle.LongDashDotDot, shape.Border.LineStyle); - Assert.AreEqual(eCompundLineStyle.Double, shape.Border.CompoundLineStyle); + Assert.AreEqual(eCompoundLineStyle.Double, shape.Border.CompoundLineStyle); Assert.AreEqual(eLineJoin.Miter, shape.Border.Join); Assert.AreEqual(10000, shape.Border.MiterJoinLimit); Assert.AreEqual(eLineCap.Flat, shape.Border.LineCap); diff --git a/src/EPPlusTest/Drawing/Chart/DataPointsTest.cs b/src/EPPlusTest/Drawing/Chart/DataPointsTest.cs index 36b732c838..dd7685b1b2 100644 --- a/src/EPPlusTest/Drawing/Chart/DataPointsTest.cs +++ b/src/EPPlusTest/Drawing/Chart/DataPointsTest.cs @@ -93,7 +93,7 @@ public void BarChart() point.Border.Fill.Style = eFillStyle.SolidFill; point.Fill.Style = eFillStyle.SolidFill; point.Fill.SolidFill.Color.SetRgbColor(Color.Yellow); - point.Fill.Transparancy = 5; + point.Fill.Transparency = 5; Assert.AreEqual(eColorTransformType.Alpha, point.Fill.SolidFill.Color.Transforms[0].Type); Assert.AreEqual(95, point.Fill.SolidFill.Color.Transforms[0].Value); chart.SetPosition(1, 0, 5, 0); diff --git a/src/EPPlusTest/Drawing/Chart/DatalabelTest.cs b/src/EPPlusTest/Drawing/Chart/DatalabelTest.cs index b5348fa168..b4afd3ee17 100644 --- a/src/EPPlusTest/Drawing/Chart/DatalabelTest.cs +++ b/src/EPPlusTest/Drawing/Chart/DatalabelTest.cs @@ -3,6 +3,7 @@ using OfficeOpenXml.Drawing.Chart; using System; using System.Drawing; +using System.Linq; namespace EPPlusTest.Drawing.Chart { diff --git a/src/EPPlusTest/Drawing/Chart/ExcelChartAxisTest.cs b/src/EPPlusTest/Drawing/Chart/ExcelChartAxisTest.cs index f8a7c3e38c..3ccc455a89 100644 --- a/src/EPPlusTest/Drawing/Chart/ExcelChartAxisTest.cs +++ b/src/EPPlusTest/Drawing/Chart/ExcelChartAxisTest.cs @@ -52,7 +52,7 @@ public void Initialize() xmlNsm.AddNamespace("a", ExcelPackage.schemaDrawings); var node = xmlDoc.CreateElement("axis"); xmlDoc.DocumentElement.AppendChild(node); - axis = new ExcelChartAxisStandard(null, xmlNsm, node, "c"); + axis = new ExcelChartAxisStandard(null, xmlNsm, node, "c", 0); p = OpenPackage("AxisDataSheet.xlsx", true); @@ -270,7 +270,7 @@ public void MultipleCategoriesOnAxesColumn() using (var p = OpenPackage("CreateEmployeesAndSales.xlsx", true)) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - var headers = new List { "Hire Date", "Employee Name", "Employee Position", "Sales This Year" }; + var headers = new List { "Hire Date", "Employee Name", "Employee TranslationOffset", "Sales This Year" }; var headRange = ws.Cells["A1:D1"]; headRange.FillList(headers, x => @@ -545,7 +545,7 @@ public void SecondaryAxis() var serie2 = chartType2.Series.Add(Worksheet.Cells["C1:C4"], Worksheet.Cells["A1:A4"]); chartType2.UseSecondaryAxis = true; - //By default the secondary X axis is hidden. If you what to show it, try this... + //By default the secondary Left axis is hidden. If you what to show it, try this... chartType2.XAxis.Deleted = false; chartType2.XAxis.TickLabelPosition = eTickLabelPosition.High; diff --git a/src/EPPlusTest/Drawing/Chart/Styling/LineChartStylingTest.cs b/src/EPPlusTest/Drawing/Chart/Styling/LineChartStylingTest.cs index 9abf916045..44a7298003 100644 --- a/src/EPPlusTest/Drawing/Chart/Styling/LineChartStylingTest.cs +++ b/src/EPPlusTest/Drawing/Chart/Styling/LineChartStylingTest.cs @@ -249,7 +249,7 @@ private static void StyleLine3dChart(ExcelWorksheet ws, eLineChartType chartType // if (chartType != eLineChartType.Line3D) // { // serie.Marker.Style = eMarkerStyle.Circle; - // serie.Marker.Size = 17; + // serie.Marker.FontSize = 17; // } // serie.DataLabel.Position = eLabelPosition.Center; // serie.DataLabel.ShowValue = true; diff --git a/src/EPPlusTest/Drawing/Chart/Styling/StylingTest.cs b/src/EPPlusTest/Drawing/Chart/Styling/StylingTest.cs index fd048237ee..af5b4d4520 100644 --- a/src/EPPlusTest/Drawing/Chart/Styling/StylingTest.cs +++ b/src/EPPlusTest/Drawing/Chart/Styling/StylingTest.cs @@ -126,7 +126,7 @@ public void StyleLineLoaded() Assert.AreEqual(25, chart.StyleManager.Style.AxisTitle.FontReference.Color.Transforms[1].Value); Assert.AreEqual(12, chart.StyleManager.Style.AxisTitle.DefaultTextRun.Kerning); Assert.AreEqual(true, chart.StyleManager.Style.AxisTitle.DefaultTextRun.Bold); - Assert.AreEqual(9, chart.StyleManager.Style.AxisTitle.DefaultTextRun.FontSize); + Assert.AreEqual(9, chart.StyleManager.Style.AxisTitle.DefaultTextRun.Size); //CategoryAxis Assert.AreEqual(eDrawingColorType.Scheme, chart.StyleManager.Style.CategoryAxis.FontReference.Color.ColorType); @@ -137,10 +137,10 @@ public void StyleLineLoaded() Assert.AreEqual(25, chart.StyleManager.Style.CategoryAxis.FontReference.Color.Transforms[1].Value); Assert.AreEqual(12, chart.StyleManager.Style.CategoryAxis.DefaultTextRun.Kerning); Assert.AreEqual(0, chart.StyleManager.Style.CategoryAxis.DefaultTextRun.Baseline); - Assert.AreEqual(9, chart.StyleManager.Style.CategoryAxis.DefaultTextRun.FontSize); + Assert.AreEqual(9, chart.StyleManager.Style.CategoryAxis.DefaultTextRun.Size); Assert.AreEqual(eTextCapsType.All, chart.StyleManager.Style.CategoryAxis.DefaultTextRun.Capitalization); Assert.AreEqual(ePenAlignment.Center, chart.StyleManager.Style.CategoryAxis.Border.Alignment); - Assert.AreEqual(eCompundLineStyle.Single, chart.StyleManager.Style.CategoryAxis.Border.CompoundLineStyle); + Assert.AreEqual(eCompoundLineStyle.Single, chart.StyleManager.Style.CategoryAxis.Border.CompoundLineStyle); Assert.AreEqual(eLineCap.Flat, chart.StyleManager.Style.CategoryAxis.Border.LineCap); Assert.AreEqual(1.5, chart.StyleManager.Style.CategoryAxis.Border.Width); Assert.AreEqual(eFillStyle.SolidFill, chart.StyleManager.Style.CategoryAxis.Border.Fill.Style); diff --git a/src/EPPlusTest/Drawing/CopyDrawingTests.cs b/src/EPPlusTest/Drawing/CopyDrawingTests.cs index 1ab47a2d51..c74bdd0c79 100644 --- a/src/EPPlusTest/Drawing/CopyDrawingTests.cs +++ b/src/EPPlusTest/Drawing/CopyDrawingTests.cs @@ -63,7 +63,7 @@ public void CopyShapeBlipFillTest() SaveAndCleanup(p); } - //Copy Picture Tests + //Copy Blip Tests [TestMethod] public void CopyPictureSameWorksheetTest() { @@ -692,7 +692,7 @@ public void CopyImagesBetweenTwo_Saved_Workbooks_NamedRanges() Assert.AreEqual("epplusPicture", wsSecond.Drawings[1].Name); Assert.AreEqual("screenshotPicture", wsFirst.Drawings[1].Name); - //Assert.AreEqual("1", wsFirst.Drawings[2].As.Picture.Part._rels["0"].Id); + //Assert.AreEqual("1", wsFirst.Drawings[2].As.Blip.Part._rels["0"].Id); var outputName = GetOutputFile("", "copy_" + target.File.Name).FullName; target.SaveAs(outputName); @@ -760,7 +760,6 @@ public void CopyNamedRangeToTargetSheetWB(ExcelPackage src, ExcelPackage target, target.Workbook.Worksheets.Delete(tmpWs); } - [TestMethod] public void s814CopySameImageTwiceToEmptyNamedRanges() { diff --git a/src/EPPlusTest/Drawing/DrawingRichTextTests.cs b/src/EPPlusTest/Drawing/DrawingRichTextTests.cs index 8855753fee..48b37e4092 100644 --- a/src/EPPlusTest/Drawing/DrawingRichTextTests.cs +++ b/src/EPPlusTest/Drawing/DrawingRichTextTests.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OfficeOpenXml; using OfficeOpenXml.Drawing; +using System.Collections.Generic; +using System.Drawing; using System.IO; namespace EPPlusTest.Drawing @@ -79,8 +81,8 @@ public void AddThreeParagraphsAndValidate() [TestMethod] public void ReadThreeParagraphsAndValidate() { - AssertIfNotExists("DrawingRichTextRead.xlsx"); - using (var p = OpenPackage("DrawingRichTextRead.xlsx")) + AssertIfNotExists("DrawingRichTextReadFunctional.xlsx"); + using (var p = OpenPackage("DrawingRichTextReadFunctional.xlsx")) { var shape = (ExcelShape)p.Workbook.Worksheets[0].Drawings["shape1"]; Assert.AreEqual("Line1\r\nLine2\r\nLine3", shape.Text); @@ -117,6 +119,134 @@ public void AddEmptyParagraphFirst() Assert.AreEqual("SecondLine", shape.RichText[1].Text); Assert.AreEqual(" ", shape.RichText[2].Text); } + [TestMethod] + public void ReadParagraphsShapes() + { + using (var p = OpenTemplatePackage("Paragraphs.xlsx")) + { + var ws1 = p.Workbook.Worksheets[0]; + var pg1 = ws1.Drawings[0].As.Shape.TextBody.Paragraphs; + + Assert.AreEqual(7, pg1.Count); + Assert.AreEqual(eDrawingColorType.Rgb, pg1[0].Bullet.Color.ColorType); + Assert.IsNotNull(pg1[0].Bullet.Color.RgbColor); + Assert.AreEqual("Wingdings", pg1[0].Bullet.Font.Typeface); + Assert.AreEqual("05000000000000000000", pg1[0].Bullet.Font.Panose); + Assert.AreEqual(ePitchFamily.Variable, pg1[0].Bullet.Font.PitchFamily); + Assert.AreEqual(2, pg1[0].Bullet.Font.Charset); + Assert.IsTrue(pg1[2].DefaultRunProperties.IsEmpty); + + + var pg2 = ws1.Drawings[1].As.Shape.TextBody.Paragraphs; + Assert.AreEqual(2, pg2[0].TabStops.Count); + Assert.AreEqual(eTabStopParagraphAlignment.Decimal, pg2[0].TabStops[0].Alignment); + } + } + [TestMethod] + public void AddParagraphsToShapes() + { + using (var p = OpenPackage("AddParagraphs.xlsx", true)) + { + var ws1 = p.Workbook.Worksheets.Add("sheet1"); + var shp = ws1.Drawings.AddShape("Shape1", eShapeStyle.Rect); + shp.TextBody.TextAutofit = eTextAutofit.ShapeAutofit; + shp.TextBody.Anchor = eTextAnchoringType.Top; + Assert.AreEqual(0, shp.RichText.Count); + var pg1 = shp.TextBody.Paragraphs.Add("Paragraph"); + pg1.HorizontalAlignment = eTextAlignment.Center; + var tr1 = pg1.TextRuns[0]; + var tr2 = pg1.TextRuns.Add(" 1"); + tr1.Fill.Color = Color.Green; + tr2.Fill.Color = Color.Red; + + var pg2 = shp.TextBody.Paragraphs.Add("This is paragraph 2"); + pg2.HorizontalAlignment = eTextAlignment.Right; + pg2.TextRuns[0].FontSize = 18; + pg2.TextRuns[0].HighlightColor.SetPresetColor(ePresetColor.Aqua); + pg1.DefaultRunProperties.LatinFont = "Arial"; + Assert.AreEqual("Paragraph 1\r\nThis is paragraph 2", shp.Text); + SaveAndCleanup(p); + } + } + [TestMethod] + public void ReadParagraphsCharts() + { + using (var p = OpenTemplatePackage("ChartForSvg.xlsx")) + { + var ws1 = p.Workbook.Worksheets[0]; + var pg = ws1.Drawings[1].As.Chart.LineChart.Title.TextBody.Paragraphs; + + Assert.IsNull(pg[0].DefaultTabSize); + Assert.AreEqual(eTextAlignment.Right, pg[0].HorizontalAlignment); + Assert.AreEqual(18, pg[0].DefaultRunProperties.Size); + Assert.IsFalse(pg[0].DefaultRunProperties.Italic); + Assert.AreEqual(OfficeOpenXml.Style.eDrawingTextLineSpacing.Single, pg[0].LineSpacing.LineSpacingType); + Assert.AreEqual(100D, pg[0].LineSpacing.Value); + Assert.AreEqual(0D, pg[0].SpaceAfter.Value); + Assert.AreEqual(0D, pg[0].SpaceBefore.Value); + Assert.IsFalse(pg[0].DefaultRunProperties.IsEmpty); + Assert.IsTrue(pg[1].DefaultRunProperties.IsEmpty); + } + } + + /// + /// Design principle: The default font stays. + /// If you set a default paragraph Font then un-specified fonts will fall-back to that font + /// The last used font of a previous text-run is NOT automatically applied as Excel might. + /// This as if unspecified for a text-run it is assumed a user would want to use the default font for the paragraph. + /// + [TestMethod] + public void TextInShape() + { + using (var p = OpenPackage("TestTextInShapeNew.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ShapeWorksheet"); + + var sunShape = ws.Drawings.AddShape("Sun", eShapeStyle.Sun); + + sunShape.Font.SetFromFont("Calibri", 14, true); + + sunShape.SetSize(500, 500); + + var rt1 = sunShape.RichText.Add("Text One", true); + + var rt2 = sunShape.RichText.Add("SubText One", false); + + rt2.LatinFont = "Algerian"; + + var latinFontForRun = rt2.LatinFont; + + var rt3 = sunShape.RichText.Add("SubText two", false); + + var rt21 = sunShape.RichText.Add("Text Two", true); + + Assert.AreEqual("Calibri", rt21.LatinFont); + Assert.AreEqual(14f, rt21.Size); + + Assert.AreEqual("Calibri", sunShape.TextBody.Paragraphs[1].DefaultRunProperties.LatinFont); + Assert.AreEqual(14, sunShape.TextBody.Paragraphs[1].DefaultRunProperties.Size); + + var rt22 = sunShape.RichText.Add("\r\n Subtext TwoOne \r\n", false); + + var size = rt22.Size; + + rt22.LatinFont = "Algerian"; + rt22.Size = 12; + rt22.Color = Color.Red; + rt22.Bold = false; + rt22.Italic = true; + + Assert.AreEqual("Algerian", rt22.LatinFont); + Assert.AreEqual(12f, rt22.Size); + + var rt23 = sunShape.RichText.Add("Subtext TwoTwo", false); + + Assert.AreEqual("Calibri", rt23.LatinFont); + Assert.AreEqual(14f, rt23.Size); + + SaveAndCleanup(p); + } + } } } } diff --git a/src/EPPlusTest/Drawing/DrawingTest.cs b/src/EPPlusTest/Drawing/DrawingTest.cs index 6d955de729..6f3de378ee 100644 --- a/src/EPPlusTest/Drawing/DrawingTest.cs +++ b/src/EPPlusTest/Drawing/DrawingTest.cs @@ -95,7 +95,7 @@ public void Picture() pic.Border.Fill.Color = Color.DarkCyan; pic.Fill.Style = eFillStyle.SolidFill; pic.Fill.Color = Color.White; - pic.Fill.Transparancy = 50; + pic.Fill.Transparency = 50; pic = ws.Drawings.AddPicture("Pic3", Resources.Test1); pic.SetPosition(400, 200); @@ -328,7 +328,7 @@ public void Scatter() chrt.Title.Fill.Style = eFillStyle.SolidFill; chrt.Title.Fill.Color = Color.LightBlue; - chrt.Title.Fill.Transparancy = 50; + chrt.Title.Fill.Transparency = 50; chrt.VaryColors = true; ExcelScatterChartSerie ser = chrt.Series[0] as ExcelScatterChartSerie; ser.DataLabel.Position = eLabelPosition.Center; @@ -630,13 +630,16 @@ public void Drawings() int y = 100, i = 1; foreach (eShapeStyle style in Enum.GetValues(typeof(eShapeStyle))) { - var shape = ws.Drawings.AddShape("shape" + i.ToString(), style); - Assert.AreEqual(eDrawingType.Shape, shape.DrawingType); - shape.SetPosition(y, 100); - shape.SetSize(300, 300); - y += 400; - shape.Text = style.ToString(); - i++; + if (style != eShapeStyle.CustomShape) + { + var shape = ws.Drawings.AddShape("shape" + i.ToString(), style); + Assert.AreEqual(eDrawingType.Shape, shape.DrawingType); + shape.SetPosition(y, 100); + shape.SetSize(300, 300); + y += 400; + shape.Text = style.ToString(); + i++; + } } (ws.Drawings["shape1"] as ExcelShape).TextAnchoring = eTextAnchoringType.Top; @@ -661,7 +664,7 @@ public void Drawings() (ws.Drawings["shape5"] as ExcelShape).Fill.Style = eFillStyle.SolidFill; (ws.Drawings["shape5"] as ExcelShape).Fill.Color = Color.Red; - (ws.Drawings["shape5"] as ExcelShape).Fill.Transparancy = 50; + (ws.Drawings["shape5"] as ExcelShape).Fill.Transparency = 50; (ws.Drawings["shape6"] as ExcelShape).Fill.Style = eFillStyle.NoFill; (ws.Drawings["shape6"] as ExcelShape).Font.Fill.Color = Color.Black; @@ -671,7 +674,7 @@ public void Drawings() (ws.Drawings["shape7"] as ExcelShape).Fill.Color = Color.Gray; (ws.Drawings["shape7"] as ExcelShape).Border.Fill.Style = eFillStyle.SolidFill; (ws.Drawings["shape7"] as ExcelShape).Border.Fill.Color = Color.Black; - (ws.Drawings["shape7"] as ExcelShape).Border.Fill.Transparancy = 43; + (ws.Drawings["shape7"] as ExcelShape).Border.Fill.Transparency = 43; (ws.Drawings["shape7"] as ExcelShape).Border.LineCap = eLineCap.Round; (ws.Drawings["shape7"] as ExcelShape).Border.LineStyle = eLineStyle.LongDash; (ws.Drawings["shape7"] as ExcelShape).Font.UnderLineColor = Color.Blue; @@ -1219,6 +1222,124 @@ public void AddTextBox() } } [TestMethod] + public void s868() + { + using (var package = OpenTemplatePackage("s868.xlsx")) + { + var wb = package.Workbook; + var ws = wb.Worksheets["aliss"]; + wb.Worksheets.Add("AlissCopy", ws); + ws.Cells["CW151"].Calculate(); + var v = ws.Cells["CW151"].Value; + SaveAndCleanup(package); + } + } + [TestMethod] + public void RichTextValidation() + { + using ( var p = OpenTemplatePackage("alignment in richtext.xlsx")) + { + var ws = p.Workbook.Worksheets["Sheet1"]; + var d = ws.Drawings[0].As.Shape; + + Assert.AreEqual(7, d.RichText.Count); + Assert.AreEqual(3, d.TextBody.Paragraphs.Count); + Assert.AreEqual("Rad 1", d.TextBody.Paragraphs[0].Text); + + Assert.AreEqual(eTextAlignment.Right, d.TextBody.Paragraphs[0].HorizontalAlignment); + Assert.AreEqual(eTextAlignment.Center, d.TextBody.Paragraphs[1].HorizontalAlignment); + Assert.AreEqual(eTextAlignment.Left, d.TextBody.Paragraphs[2].HorizontalAlignment); + + Assert.AreEqual(2, d.TextBody.Paragraphs[0].TextRuns.Count); + Assert.AreEqual("Rad", d.TextBody.Paragraphs[0].TextRuns[0].Text); + Assert.AreEqual(" 1", d.TextBody.Paragraphs[0].TextRuns[1].Text); + } + } + + [TestMethod] + public void ChangeUnderlineShapeTextRun() + { + string outputFileName = "UnderlineChange_SuperAndSubscript.xlsx"; + using (var p = OpenTemplatePackage("SuperAndSubScript.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + + var currShape = ws.Drawings[0]; + + var paragraph = currShape.As.Shape.TextBody.Paragraphs[0]; + paragraph.TextRuns[2].UnderLineColor = Color.Red; + + var file = GetOutputFile("", outputFileName); + p.SaveAs(file); + } + + using(var p = OpenPackage(outputFileName)) + { + var ws = p.Workbook.Worksheets[0]; + + var currShape = ws.Drawings[0]; + + var paragraph = currShape.As.Shape.TextBody.Paragraphs[0]; + Assert.AreEqual(Color.Red.ToArgb(), paragraph.TextRuns[2].UnderLineColor.ToArgb()); + } + } + + [TestMethod] + public void GenerateAndChangeUnderlineShapeTextRunEpplus() + { + string outputFileName = "UnderlineChange_Generated.xlsx"; + + //Generate file + using (var p = OpenPackage("UnderlineChange_Shape.xlsx",true)) + { + var ws = p.Workbook.Worksheets.Add("ws1"); + + var box = ws.Drawings.AddTextbox("boxy", "Boxy is kind"); + + box.Fill.Color = Color.DarkKhaki; + + box.TextBody.Paragraphs[0].TextRuns[0].FontUnderLine = eUnderLineType.Heavy; + box.TextBody.Paragraphs[0].TextRuns[0].UnderLineColor = Color.DarkRed; + + var file = GetOutputFile("", outputFileName); + + p.SaveAs(file); + + var file2 = GetOutputFile("", "UnderlineChange_Shape.xlsx"); + p.SaveAs(file2); + } + + //Open file, verify color, save with new color + using (var p = OpenPackage(outputFileName)) + { + var ws = p.Workbook.Worksheets[0]; + + var currShape = ws.Drawings[0]; + + var paragraph = currShape.As.Shape.TextBody.Paragraphs[0]; + var textRun = paragraph.TextRuns[0]; + Assert.AreEqual(Color.DarkRed.ToArgb(), textRun.UnderLineColor.ToArgb()); + + textRun.UnderLineColor = Color.Chartreuse; + + SaveAndCleanup(p); + } + + //Open file, verify color + using (var p = OpenPackage(outputFileName)) + { + var ws = p.Workbook.Worksheets[0]; + + var currShape = ws.Drawings[0]; + + var paragraph = currShape.As.Shape.TextBody.Paragraphs[0]; + var textRun = paragraph.TextRuns[0]; + Assert.AreEqual(Color.Chartreuse.ToArgb(), textRun.UnderLineColor.ToArgb()); + + SaveAndCleanup(p); + } + } + [TestMethod] public void DrawingNameChangeAndRemovalTest() { using (var package = new ExcelPackage()) diff --git a/src/EPPlusTest/Drawing/Style/DrawingParagraphTests.cs b/src/EPPlusTest/Drawing/Style/DrawingParagraphTests.cs new file mode 100644 index 0000000000..9b4e56d2ae --- /dev/null +++ b/src/EPPlusTest/Drawing/Style/DrawingParagraphTests.cs @@ -0,0 +1,41 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; +using OfficeOpenXml.Drawing.Style.Coloring; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Reflection; +using System.Text; + +namespace EPPlusTest.Drawing.Style +{ + [TestClass] + public class DrawingParagraphTests: TestBase + { + [TestMethod] + public void EnsureExpectedParagraphCount() + { + using(var p = OpenPackage("DrawingParagraphCount.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("shapeParagraphs"); + var shape = ws.Drawings.AddShape("shape1", eShapeStyle.Sun); + + shape.Font.SetFromFont("Aptos Narrow", 11f); + var font = shape.Font; + font.Color = Color.Goldenrod; + + var paragraphs = shape.TextBody.Paragraphs; + + var para1 = paragraphs.Add("hello the most"); + + var para2 = paragraphs.Add(" "); + var para3 = paragraphs.Add("people"); + + Assert.AreEqual(3, paragraphs.Count); + + SaveAndCleanup(p); + } + } + } +} diff --git a/src/EPPlusTest/Drawing/Style/FillReadTest.cs b/src/EPPlusTest/Drawing/Style/FillReadTest.cs index 4d1a91f029..de82a90eaf 100644 --- a/src/EPPlusTest/Drawing/Style/FillReadTest.cs +++ b/src/EPPlusTest/Drawing/Style/FillReadTest.cs @@ -168,7 +168,7 @@ public void ReadSolidFill_ColorSystem() public void ReadTransparancy() { //Setup - var wsName = "Transparancy"; + var wsName = "Transparency"; var expected = 45; var ws = _pck.Workbook.Worksheets[wsName]; if (ws == null) Assert.Inconclusive($"{wsName} worksheet is missing"); @@ -176,7 +176,7 @@ public void ReadTransparancy() //Assert Assert.AreEqual(eFillStyle.SolidFill, shape.Fill.Style); - Assert.AreEqual(expected, shape.Fill.Transparancy); + Assert.AreEqual(expected, shape.Fill.Transparency); Assert.AreEqual(eColorTransformType.Alpha, shape.Fill.SolidFill.Color.Transforms[0].Type); Assert.AreEqual(100 - expected, shape.Fill.SolidFill.Color.Transforms[0].Value); } @@ -192,7 +192,7 @@ public void ReadTransformAlpha() //Assert Assert.AreEqual(eFillStyle.SolidFill, shape.Fill.Style); - Assert.AreEqual(100 - expected, shape.Fill.Transparancy); + Assert.AreEqual(100 - expected, shape.Fill.Transparency); Assert.AreEqual(eColorTransformType.Alpha, shape.Fill.SolidFill.Color.Transforms[0].Type); Assert.AreEqual(expected, shape.Fill.SolidFill.Color.Transforms[0].Value); } diff --git a/src/EPPlusTest/Drawing/Style/FillTest.cs b/src/EPPlusTest/Drawing/Style/FillTest.cs index e5dd9c9f20..4bfdf6f04d 100644 --- a/src/EPPlusTest/Drawing/Style/FillTest.cs +++ b/src/EPPlusTest/Drawing/Style/FillTest.cs @@ -242,19 +242,19 @@ public void Transparancy() { //Setup var expected = 45; - var ws = _pck.Workbook.Worksheets.Add("Transparancy"); + var ws = _pck.Workbook.Worksheets.Add("Transparency"); var shape = ws.Drawings.AddShape("Shape1", eShapeStyle.Rect); shape.SetPosition(1, 0, 5, 0); //Act shape.Fill.Color = Color.Red; - shape.Fill.Transparancy = expected; + shape.Fill.Transparency = expected; //Assert Assert.AreEqual(eFillStyle.SolidFill, shape.Fill.Style); Assert.IsInstanceOfType(shape.Fill.SolidFill.Color.RgbColor, typeof(ExcelDrawingRgbColor)); - Assert.AreEqual(expected, shape.Fill.Transparancy); + Assert.AreEqual(expected, shape.Fill.Transparency); Assert.AreEqual(100 - expected, shape.Fill.SolidFill.Color.Transforms[0].Value); } [TestMethod] @@ -274,7 +274,7 @@ public void TransformAlpha() //Assert Assert.AreEqual(eFillStyle.SolidFill, shape.Fill.Style); Assert.IsInstanceOfType(shape.Fill.SolidFill.Color.RgbColor, typeof(ExcelDrawingRgbColor)); - Assert.AreEqual(100 - expected, shape.Fill.Transparancy); + Assert.AreEqual(100 - expected, shape.Fill.Transparency); Assert.AreEqual(eColorTransformType.Alpha, shape.Fill.SolidFill.Color.Transforms[0].Type); Assert.AreEqual(expected, shape.Fill.SolidFill.Color.Transforms[0].Value); } diff --git a/src/EPPlusTest/Drawing/TextMeasuring/ReadMeasureTests.cs b/src/EPPlusTest/Drawing/TextMeasuring/ReadMeasureTests.cs new file mode 100644 index 0000000000..1eef5b295d --- /dev/null +++ b/src/EPPlusTest/Drawing/TextMeasuring/ReadMeasureTests.cs @@ -0,0 +1,173 @@ +using EPPlusImageRenderer; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml; +using OfficeOpenXml.Drawing; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using EPPlus.Fonts.OpenType; +using OfficeOpenXml.Interfaces.Drawing.Text; +using EPPlus.Fonts.OpenType.Utils; + + +namespace EPPlusTest.Drawing.TextMeasuring +{ + [TestClass] + public class ReadMeasureTests: TestBase + { + [TestMethod] + public void ReadShape() + { + using(var p = OpenTemplatePackage("ReadText.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var theShape = ws.Drawings[0].As.Shape; + + ws.Calculate(); + theShape.AdjustPositionAndSize(); + + var width = theShape.Size.Width / 9525d; + var height = theShape.Size.Height / 9525d; + //var height = theShape.TextBodyItem.Paragraphs.GetSizeInPixels(theShape.GetPixelWidth(), theShape.GetPixelHeight(), theShape.Text, theShape.Font); + } + } + [TestMethod] + public void ReadLoremIpsum() + { + using (var p = OpenTemplatePackage("LoremIpsums20.xlsx")) + { + var ws1 = p.Workbook.Worksheets[0]; + var shape1 = ws1.Drawings[0].As.Shape; + var someText = shape1.TextBody.Paragraphs; + } + } + + internal List SplitIntoLines(string text) + { + return text.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList(); + } + + [TestMethod] + public void WrapMultipleFragments_SpacedEndWord() + { + List txtRuns = + [ + "H", + "IJ", + "K", + "L", + "M ", + "NOPE", + ]; + + + var mf = new MeasurementFont(); + mf.FontFamily = "Aptos Narrow"; + mf.Style = MeasurementFontStyles.Regular; + mf.Size = 16; + + var mf2 = new MeasurementFont(); + mf2.FontFamily = "Goudy Stout"; + mf2.Style = MeasurementFontStyles.Regular; + mf2.Size = 11; + + List fonts = + [ + mf, + mf, + mf, + mf, + mf + ]; + + fonts.Add(mf2); + + var txtMeasurer = OpenTypeFonts.GetTextLayoutEngineForFont(mf2); + var maxWidth = 114d; + + var wrappedFragments = txtMeasurer.WrapRichText(txtRuns, fonts, maxWidth.PixelToPoint()); + + Assert.AreEqual(2, wrappedFragments.Count); + Assert.AreEqual("HIJKLM", wrappedFragments[0]); + Assert.AreEqual("NOPE", wrappedFragments[1]); + } + + [TestMethod] + public void WrapMultipleFragments_LongPlusEndWord() + { + List txtRuns = + [ + "H", + "IJ", + "K", + "L", + "Mpqrstvdef", + " ", + "NOPE", + ]; + + + var mf = new MeasurementFont(); + mf.FontFamily = "Aptos Narrow"; + mf.Style = MeasurementFontStyles.Regular; + mf.Size = 16; + + var mf2 = new MeasurementFont(); + mf2.FontFamily = "Aptos Narrow"; + mf2.Style = MeasurementFontStyles.Regular; + mf2.Size = 11; + + List fonts = + [ + mf, + mf, + mf, + mf, + mf + ]; + + fonts.Add(mf2); + fonts.Add(mf2); + + var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); + var txtMeasurer = engine.GetTextLayoutEngineForFont(mf); + + var maxWidth = 114d; + + var wrappedFragments = txtMeasurer.WrapRichText(txtRuns, fonts, maxWidth.PixelToPoint()); + + Assert.AreEqual(2, wrappedFragments.Count); + Assert.AreEqual("HIJKLMpqrst", wrappedFragments[0]); + Assert.AreEqual("vdef NOPE", wrappedFragments[1]); + } + + [TestMethod] + public void ReadRichTextBox() + { + using (var p = OpenTemplatePackage("paragraphBook.xlsx")) + { + var ws1 = p.Workbook.Worksheets[0]; + var shape1 = ws1.Drawings[0].As.Shape; + var paragraphs = shape1.TextBody.Paragraphs; + var someText = shape1.TextBody.Paragraphs.Text; + var richText = shape1.RichText; + + shape1.GetSizeInPixels(out int width, out int height); + + var svg = shape1.ToSvg(); + + var svgFile = GetOutputFile("", "paragraphBook.svg"); + + //Create a file to write to. + using (StreamWriter sw = svgFile.CreateText()) + { + sw.Write(svg); + } + + SaveAndCleanup(p); + } + } + } +} diff --git a/src/EPPlusTest/Drawing/ThemeTest.cs b/src/EPPlusTest/Drawing/ThemeTest.cs index a1bb671dad..55643c9b6e 100644 --- a/src/EPPlusTest/Drawing/ThemeTest.cs +++ b/src/EPPlusTest/Drawing/ThemeTest.cs @@ -236,7 +236,7 @@ public void LoadThmx_BordersScheme() Assert.AreEqual(eLineStyle.Solid, currentTheme.FormatScheme.BorderStyle[0].Style); Assert.AreEqual(ePenAlignment.Center, currentTheme.FormatScheme.BorderStyle[0].Alignment); Assert.AreEqual(eLineCap.Flat, currentTheme.FormatScheme.BorderStyle[0].Cap); - Assert.AreEqual(eCompundLineStyle.Single, currentTheme.FormatScheme.BorderStyle[0].CompoundLineStyle); + Assert.AreEqual(eCompoundLineStyle.Single, currentTheme.FormatScheme.BorderStyle[0].CompoundLineStyle); Assert.IsNull(currentTheme.FormatScheme.BorderStyle[0].HeadEnd.Width); Assert.IsNull(currentTheme.FormatScheme.BorderStyle[0].HeadEnd.Height); Assert.IsNull(currentTheme.FormatScheme.BorderStyle[0].HeadEnd.Style); diff --git a/src/EPPlusTest/EPPlus.Test.csproj b/src/EPPlusTest/EPPlus.Test.csproj index f65652daf8..e85ae97ea6 100644 --- a/src/EPPlusTest/EPPlus.Test.csproj +++ b/src/EPPlusTest/EPPlus.Test.csproj @@ -25,8 +25,10 @@ - + + + @@ -47,6 +49,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + @@ -63,6 +74,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/EPPlusTest/Export/HtmlExport/CssRuleCollectionTests.cs b/src/EPPlusTest/Export/HtmlExport/CssRuleCollectionTests.cs index 903460058e..508d2bb7b3 100644 --- a/src/EPPlusTest/Export/HtmlExport/CssRuleCollectionTests.cs +++ b/src/EPPlusTest/Export/HtmlExport/CssRuleCollectionTests.cs @@ -1,21 +1,23 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using OfficeOpenXml; -using OfficeOpenXml.Export.HtmlExport.CssCollections; +using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Export.HtmlExport; +using OfficeOpenXml.Export.HtmlExport.CssCollections; +using OfficeOpenXml.Export.HtmlExport.Exporters.Internal; +using OfficeOpenXml.Export.HtmlExport.StyleCollectors; using OfficeOpenXml.Export.HtmlExport.StyleCollectors.StyleContracts; using OfficeOpenXml.Export.HtmlExport.Translators; -using OfficeOpenXml.Export.HtmlExport.StyleCollectors; +using System; +using System.Collections.Generic; using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; namespace EPPlusTest.Export.HtmlExport { [TestClass] - public class CssRuleCollectionTests + public class CssRuleCollectionTests : TestBase { [TestMethod] public void ExportRangeWithNullBorderMergedCellsShouldNotThrow() @@ -47,5 +49,73 @@ public void ExportRangeWithNullBorderMergedCellsShouldNotThrow() var declarations = borderTranslator.GenerateDeclarationList(context); } } + + [TestMethod] + public void ExportChartCssTest() + { + using (var package = new ExcelPackage()) + { + var mySheet = package.Workbook.Worksheets.Add("chartSinglSheet"); + + mySheet.Cells["A1:C1"].Formula = "COLUMN()"; + + var lChart = mySheet.Drawings.AddLineChart("chart1", eLineChartType.Line); + + mySheet.Calculate(); + + var address = mySheet.Cells["A1:C1"]; + + lChart.Series.Add(address, address); + + lChart.StyleManager.SetChartStyle(OfficeOpenXml.Drawing.Chart.Style.ePresetChartStyle.LineChartStyle2); + + lChart.Fill.Style = OfficeOpenXml.Drawing.eFillStyle.SolidFill; + lChart.Fill.Color = Color.Aquamarine; + lChart.Border.Fill.Color = Color.DarkCyan; + + lChart.StyleManager.Style.ChartArea.Fill.Style = OfficeOpenXml.Drawing.eFillStyle.SolidFill; + + //lChart.StyleManager.Style.ChartArea.Fill.Color = Color.DarkCyan; + //lChart.StyleManager.Style.ChartArea.Border.Fill.Color = Color.DarkSeaGreen; + + var cssExporter = new CssChartExporterSync(lChart); + + var css = cssExporter.GetCssString(); + + package.SaveAs("C:\\epplusTest\\Testoutput\\generatedLineChart.xlsx"); + } + } + + [TestMethod] + public void ChartTitleIssue() + { + + using (var package = OpenTemplatePackage("ChartLineDefaultDownUp.xlsx")) + { + var mySheet = package.Workbook.Worksheets[0]; + + var lChart = mySheet.Drawings[0].As.Chart.LineChart; + + lChart.StyleManager.ApplyStyles(); + + package.SaveAs("C:\\epplusTest\\Testoutput\\ChartLineDefaultApply.xlsx"); + } + + using (var package = OpenPackage("ChartLineDefaultApply.xlsx", false)) + { + var mySheet = package.Workbook.Worksheets[0]; + + var lChart = mySheet.Drawings[0].As.Chart.LineChart; + + lChart.Title.Text = "MyTitle"; + + lChart.StyleManager.ApplyStyles(); + + Assert.AreEqual("MyTitle", lChart.Title.TextBody.Paragraphs[0].Text); + Assert.AreEqual("MyTitle", lChart.Title.TextBody.Paragraphs[0].TextRuns[0].Text); + + package.SaveAs("C:\\epplusTest\\Testoutput\\ChartLineDefaultApplyAndTitle.xlsx"); + } + } } } diff --git a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs index 7e05574101..9355f2b8c4 100644 --- a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs +++ b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs @@ -140,5 +140,36 @@ public void ExportingHtmlCFsWithThemeColor() SaveAndCleanup(p); } } + + [TestMethod] + public void ExportCss() + { + ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project"); + + var chartName = "DifficultCssExportMb.xlsx"; + using (var p = OpenTemplatePackage(chartName)) + { + var ws = p.Workbook.Worksheets[0]; + + var range = ws.Cells["A1:G10"]; + + var html = range.CreateHtmlExporter(); + var fs = GetOutputFile("", "cssExportDatabarMb.html"); + + var cssStr = html.GetCssString(); + //var lChart = ws.Drawings[0].As.Chart.LineChart; + + ////lChart.Title.Font.Color = Color.DeepSkyBlue; + + //lChart.StyleManager.ApplyStyles(); + + SaveAndCleanup(p); + } + + //using(var p= OpenPackage(chartName,false)) + //{ + + //} + } } } diff --git a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs index 98ac450ee3..7ec061fb6a 100644 --- a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs +++ b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs @@ -11,6 +11,8 @@ using System.IO; using System.Text; using System.Threading.Tasks; +using System.Linq; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; namespace EPPlusTest.Export.HtmlExport { @@ -143,7 +145,6 @@ public async Task ShouldExportHtmlWithMergedCells() var resultAsync = await exporter.GetSinglePageAsync(); SaveAndCleanup(package); Assert.AreEqual(result, resultAsync); - } } [TestMethod] @@ -176,6 +177,101 @@ public void WriteAllsvenskan() SaveAndCleanup(p); } } + + [TestMethod] + public async Task TaskWriteImagesSimple() + { + using (var p = OpenTemplatePackage("SimpleImageForHtml.xlsx")) + { + var sheet = p.Workbook.Worksheets[0]; + var exporter = sheet.Cells["A1:L17"].CreateHtmlExporter(); + + exporter.Settings.SetColumnWidth = true; + exporter.Settings.SetRowHeight = true; + + var pictureSettings = exporter.Settings.Pictures; + + pictureSettings.Include = ePictureInclude.Include; + pictureSettings.Position = ePicturePosition.Relative; + pictureSettings.KeepOriginalSize = false; + + exporter.Settings.Minify = false; + exporter.Settings.Encoding = Encoding.UTF8; + var html = exporter.GetSinglePage(); + var htmlAsync = await exporter.GetSinglePageAsync(); + + var outputFile = GetOutputFile("html", "simpleImageSync3.html"); + var outputFileAsync = GetOutputFile("html", "simpleImageAsync3.html"); + + File.WriteAllText(outputFile.FullName, html); + File.WriteAllText(outputFileAsync.FullName, htmlAsync); + Assert.AreEqual(html, htmlAsync); + } + } + + [TestMethod] + public async Task TaskWriteChartAndShape() + { + using (var p = OpenTemplatePackage("ChartAndShapeHtml.xlsx")) + { + var sheet = p.Workbook.Worksheets[0]; + var exporter = sheet.Cells["A1:L17"].CreateHtmlExporter(); + + exporter.Settings.SetColumnWidth = true; + exporter.Settings.SetRowHeight = true; + + var setting = exporter.Settings.Drawings; + + setting.DrawTypeInclude = eDrawingInclude.Shapes & eDrawingInclude.Shapes; + setting.Include = ePictureInclude.Include; + setting.Position = ePicturePosition.Absolute; + + exporter.Settings.Minify = false; + exporter.Settings.Encoding = Encoding.UTF8; + var html = exporter.GetSinglePage(); + var htmlAsync = await exporter.GetSinglePageAsync(); + + var outputFile = GetOutputFile("html", "chartAndShape.html"); + var outputFileAsync = GetOutputFile("html", "chartAndShapeAsync.html"); + + File.WriteAllText(outputFile.FullName, html); + File.WriteAllText(outputFileAsync.FullName, htmlAsync); + Assert.AreEqual(html, htmlAsync); + } + } + + [TestMethod] + public async Task TaskWriteChartSimple() + { + using (var p = OpenTemplatePackage("SimpleChartForHtml.xlsx")) + { + var sheet = p.Workbook.Worksheets[0]; + var exporter = sheet.Cells["A1:L17"].CreateHtmlExporter(); + + exporter.Settings.SetColumnWidth = true; + exporter.Settings.SetRowHeight = true; + + var setting = exporter.Settings.Drawings; + + setting.DrawTypeInclude = eDrawingInclude.Charts; + setting.Include = ePictureInclude.Include; + setting.Position = ePicturePosition.Relative; + + exporter.Settings.Minify = false; + exporter.Settings.Encoding = Encoding.UTF8; + var html = exporter.GetSinglePage(); + var htmlAsync = await exporter.GetSinglePageAsync(); + + var outputFile = GetOutputFile("html", "simpleChartSync.html"); + var outputFileAsync = GetOutputFile("html", "simpleChartAsync.html"); + + File.WriteAllText(outputFile.FullName, html); + File.WriteAllText(outputFileAsync.FullName, htmlAsync); + Assert.AreEqual(html, htmlAsync); + } + } + + [TestMethod] public async Task WriteImagesAsync() { diff --git a/src/EPPlusTest/Export/HtmlExport/SvgShapeExportTests.cs b/src/EPPlusTest/Export/HtmlExport/SvgShapeExportTests.cs new file mode 100644 index 0000000000..b54ab3ff04 --- /dev/null +++ b/src/EPPlusTest/Export/HtmlExport/SvgShapeExportTests.cs @@ -0,0 +1,155 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml.Drawing.Chart.Style; +using OfficeOpenXml.Export.HtmlExport; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; + +namespace EPPlusTest.Export.HtmlExport +{ + [TestClass] + public class SvgShapeExportTests : TestBase + { + [TestMethod] + public void ExportBasicShapeWorksheet() + { + int[] values = { 5, 10, 15, 20 }; + using (var package = OpenPackage("HtmlBasicSvgShape.xlsx", true)) + { + var ws = package.Workbook.Worksheets.Add("ShapeWs"); + var rect = ws.Drawings.AddShape("SimpleRect", OfficeOpenXml.Drawing.eShapeStyle.Rect); + //rect.Fill.Color = System.Drawing.Color.AliceBlue; + //var rect2 = ws.Drawings.AddShape("SimpleRect2", OfficeOpenXml.Drawing.eShapeStyle.Rect); + //rect2.Fill.Color = System.Drawing.Color.BlanchedAlmond; + + for (int i = 0; i< values.Count()*2; i++) + { + if(i >= values.Count()) + { + ws.Cells[i+1, 1].Value = -values[i - values.Count()]; + } + else + { + ws.Cells[i+1, 1].Value = values[i]; + } + } + + var exporter = ws.Cells["A1:C20"].CreateHtmlExporter(); + + exporter.Settings.Drawings.Include = ePictureInclude.IncludeInHtmlOnly; + exporter.Settings.Drawings.DrawTypeInclude = eDrawingInclude.Shapes; + + var htmlPage = exporter.GetSinglePage(); + + var file = GetOutputFile("html", "svgRect.html"); + + SaveAndCleanup(package); + + File.WriteAllText(file.FullName, htmlPage); + } + } + + [TestMethod] + public void ExportBarChart() + { + int[] values = { 5, 10, 15, 20 }; + using (var package = OpenPackage("HtmlSvgColChart.xlsx", true)) + { + var ws = package.Workbook.Worksheets.Add("ShapeWs"); + + for (int i = 0; i < values.Count() * 2; i++) + { + if (i >= values.Count()) + { + ws.Cells[i + 1, 1].Value = -values[i - values.Count()]; + } + else + { + ws.Cells[i + 1, 1].Value = values[i]; + } + } + + var chart = ws.Drawings.AddBarChart("myColChart", OfficeOpenXml.Drawing.Chart.eBarChartType.ColumnClustered); + chart.Series.Add(ws.Cells["A1:A8"]); + + //chart.StyleManager.SetChartStyle(ePresetChartStyleMultiSeries.BarChartStyle1); + + //chart.Style = OfficeOpenXml.Drawing.Chart.eChartStyle.Style1; + //var theme = ws.Workbook.ThemeManager.GetOrCreateTheme(); + //chart.StyleManager.SetChartStyle(0); + //chart.StyleManager.SetChartStyle(0); + //chart.StyleManager.ApplyStyles(); + //chart.Fill.Color = System.Drawing.Color.BlanchedAlmond; + //chart.Series[0].Fill.Color = System.Drawing.Color.LightCoral; + + var exporter = ws.Cells["A1:C20"].CreateHtmlExporter(); + + + exporter.Settings.SetColumnWidth = true; + exporter.Settings.SetRowHeight = true; + exporter.Settings.Minify = false; + exporter.Settings.Encoding = Encoding.UTF8; + exporter.Settings.Drawings.Include = ePictureInclude.IncludeInHtmlOnly; + exporter.Settings.Drawings.DrawTypeInclude = eDrawingInclude.Charts; + + var htmlPage = exporter.GetSinglePage(); + + var file = GetOutputFile("html", "myColChart.html"); + var svgFile = GetOutputFile("html", "myColChartSvg.svg"); + + File.WriteAllText(file.FullName, htmlPage); + File.WriteAllText(svgFile.FullName, chart.ToSvg()); + + SaveAndCleanup(package); + } + } + + [TestMethod] + public void ExportBarChartWithCategories() + { + int[] values = { 5, 10, 15, 20 }; + using (var package = OpenPackage("HtmlSvgColChartCategories.xlsx", true)) + { + var ws = package.Workbook.Worksheets.Add("ShapeWs"); + + ws.Cells["A1"].Value = "Value"; + ws.Cells["B1"].Value = "Title"; + + for (int i = 0; i < values.Count() * 2; i++) + { + if (i >= values.Count()) + { + ws.Cells[i + 2, 1].Value = -values[i - values.Count()]; + } + else + { + ws.Cells[i + 2, 1].Value = values[i]; + } + } + + var chart = ws.Drawings.AddBarChart("myColChart", OfficeOpenXml.Drawing.Chart.eBarChartType.ColumnClustered); + chart.Series.Add(ws.Cells["A1:A10"]); + + chart.Fill.Color = System.Drawing.Color.BlanchedAlmond; + chart.Series[0].Fill.Color = System.Drawing.Color.LightCoral; + chart.SetPixelWidth(250); + + var exporter = ws.Cells["A1:C20"].CreateHtmlExporter(); + + exporter.Settings.Drawings.Include = ePictureInclude.IncludeInHtmlOnly; + exporter.Settings.Drawings.DrawTypeInclude = eDrawingInclude.Charts; + + var htmlPage = exporter.GetSinglePage(); + + var file = GetOutputFile("html", "colChartCats.html"); + + SaveAndCleanup(package); + + File.WriteAllText(file.FullName, htmlPage); + } + } + } +} diff --git a/src/EPPlusTest/Export/ToDataTable/ToDataTableTests.cs b/src/EPPlusTest/Export/ToDataTable/ToDataTableTests.cs index 9e6253233b..98b9348322 100644 --- a/src/EPPlusTest/Export/ToDataTable/ToDataTableTests.cs +++ b/src/EPPlusTest/Export/ToDataTable/ToDataTableTests.cs @@ -494,7 +494,7 @@ public void EnsureErrorValuesCanBeWritten() if (cellVal is ExcelErrorValue eev) { return cellVal.ToString(); - // return eev.Type; + // return eev.BulletType; } return cellVal; }); diff --git a/src/EPPlusTest/Filter/AutoFilterReadWriteTest.cs b/src/EPPlusTest/Filter/AutoFilterReadWriteTest.cs index 184e94f814..ee179397d0 100644 --- a/src/EPPlusTest/Filter/AutoFilterReadWriteTest.cs +++ b/src/EPPlusTest/Filter/AutoFilterReadWriteTest.cs @@ -51,7 +51,6 @@ public void ValuesFilter() col.Filters.Add("19"); col.Filters.Blank = true; col.Filters.Add(new ExcelFilterDateGroupItem(2018, 12)); - var col2 = ws.AutoFilter.Columns.AddValueFilterColumn(2); col2.Filters.Add("Value 6"); ws.AutoFilter.ApplyFilter(); diff --git a/src/EPPlusTest/FontTestBase.cs b/src/EPPlusTest/FontTestBase.cs new file mode 100644 index 0000000000..bc1609d1cf --- /dev/null +++ b/src/EPPlusTest/FontTestBase.cs @@ -0,0 +1,21 @@ +using EPPlus.Fonts.OpenType; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EPPlusTest +{ + public class FontTestBase : TestBase + { + protected string FontFolder + { + get + { + return Path.Combine(AppContext.BaseDirectory, "Fonts"); + } + } + } +} diff --git a/src/EPPlusTest/Fonts/BIZUDGothic-Regular.ttf b/src/EPPlusTest/Fonts/BIZUDGothic-Regular.ttf new file mode 100644 index 0000000000..030a7c96fd Binary files /dev/null and b/src/EPPlusTest/Fonts/BIZUDGothic-Regular.ttf differ diff --git a/src/EPPlusTest/Fonts/OpenSans-Regular.ttf b/src/EPPlusTest/Fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000000..134d225f66 Binary files /dev/null and b/src/EPPlusTest/Fonts/OpenSans-Regular.ttf differ diff --git a/src/EPPlusTest/Fonts/Roboto-Regular.ttf b/src/EPPlusTest/Fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000..ddf4bfacb3 Binary files /dev/null and b/src/EPPlusTest/Fonts/Roboto-Regular.ttf differ diff --git a/src/EPPlusTest/FormulaParsing/CalculateCompareDirectoryTest.cs b/src/EPPlusTest/FormulaParsing/CalculateCompareDirectoryTest.cs index a010423abd..891cfe7893 100644 --- a/src/EPPlusTest/FormulaParsing/CalculateCompareDirectoryTest.cs +++ b/src/EPPlusTest/FormulaParsing/CalculateCompareDirectoryTest.cs @@ -80,11 +80,12 @@ public void VerifyCalculationInCalculateTestDirectory() private void VerifyCalculationInPackage(string xlFile, string logFile) { Stopwatch sw = new Stopwatch(); - sw.Start(); - if(File.Exists(logFile)) + sw.Start(); + if(File.Exists(logFile)) { - File.Delete(logFile); + File.Delete(logFile); } + var extension = Path.GetExtension(xlFile); var logWriter = new StreamWriter(File.OpenWrite(logFile)); diff --git a/src/EPPlusTest/FormulaParsing/Excel/CalcErrorTests.cs b/src/EPPlusTest/FormulaParsing/Excel/CalcErrorTests.cs index 2b2feccaf8..c29410f0a7 100644 --- a/src/EPPlusTest/FormulaParsing/Excel/CalcErrorTests.cs +++ b/src/EPPlusTest/FormulaParsing/Excel/CalcErrorTests.cs @@ -30,7 +30,6 @@ public void CalcErrorWhenEmptyFilterFunction() Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Calc), sheet.Cells["E4"].Value); //SaveWorkbook("CalcError1.xlsx", package); } - [TestMethod] public void CalcErrorWhenUnInvokedLambda() { diff --git a/src/EPPlusTest/FormulaParsing/Excel/Functions/RefAndLookup/ImageFunctionTests.cs b/src/EPPlusTest/FormulaParsing/Excel/Functions/RefAndLookup/ImageFunctionTests.cs index eff68ac678..802089dd55 100644 --- a/src/EPPlusTest/FormulaParsing/Excel/Functions/RefAndLookup/ImageFunctionTests.cs +++ b/src/EPPlusTest/FormulaParsing/Excel/Functions/RefAndLookup/ImageFunctionTests.cs @@ -54,7 +54,6 @@ public void ImageTest_WithReference() Assert.AreEqual(CalcOrigins.Reference, pic2.CalcOrigin); SaveWorkbook("ImageFunctionTest_Reference.xlsx", package); } - [TestMethod] public void ImageTest_AltText() { diff --git a/src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/TrendTest.cs b/src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/TrendTest.cs index ef8b04ccb3..1e14b9523a 100644 --- a/src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/TrendTest.cs +++ b/src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/TrendTest.cs @@ -434,7 +434,7 @@ public void TrendShouldHandleThreeRanges() // ExcelWorksheet worksheet = package.Workbook.Worksheets[0]; // worksheet.Cells["O1"].Value = "EPPLUS RESULT"; - // worksheet.Cells["O1"].Style.Font.Bold = true; + // worksheet.Cells["O1"].Style.Font.FontBold = true; // worksheet.Cells["O2"].Formula = "TREND(A2:A1001, B2:F1001, G2:K1001, FALSE)"; // worksheet.Calculate(); // for (int i = 2; i < 1002; i++ ) diff --git a/src/EPPlusTest/FormulaParsing/ExpressionGraph/ExcelTableExpressionTests.cs b/src/EPPlusTest/FormulaParsing/ExpressionGraph/ExcelTableExpressionTests.cs index 29c99dae4f..2a9d21f6bc 100644 --- a/src/EPPlusTest/FormulaParsing/ExpressionGraph/ExcelTableExpressionTests.cs +++ b/src/EPPlusTest/FormulaParsing/ExpressionGraph/ExcelTableExpressionTests.cs @@ -106,7 +106,7 @@ public void VerifyTableExpression_Table_With_NonExisting_Worksheet() //Assert.AreEqual(1, exps.Expressions.Count); //Assert.AreEqual(TokenType.TableName, tokens[4].TokenType); - //var result = ((TableAddressExpression)exps.Expressions[0].Children[0].Children[0]).Compile(); + //var result = ((TableAddressExpression)exps.Expressions[0].ChartAreaRenderItems[0].ChartAreaRenderItems[0]).Compile(); //var range = (IRangeInfo)result.Result; //Assert.AreEqual("#REF!", range.Address.WorksheetAddress); @@ -130,7 +130,7 @@ public void VerifyTableExpression_External_Table() //Assert.AreEqual(1, exps.Expressions.Count); //Assert.AreEqual(TokenType.TableName, tokens[7].TokenType); - //var result = ((TableAddressExpression)exps.Expressions[0].Children[0].Children[0]).Compile(); + //var result = ((TableAddressExpression)exps.Expressions[0].ChartAreaRenderItems[0].ChartAreaRenderItems[0]).Compile(); //var range = (IRangeInfo)result.Result; //Assert.AreEqual(range.Address.FromRow, 2); @@ -160,7 +160,7 @@ public void VerifyTableExpression_Table_And_CellAddress() //Assert.AreEqual(1, exps.Expressions.Count); //Assert.AreEqual(TokenType.TableName, tokens[4].TokenType); - //var addressResult = exps.Expressions[0].Children[0].Children[0].Compile(); + //var addressResult = exps.Expressions[0].ChartAreaRenderItems[0].ChartAreaRenderItems[0].Compile(); //Assert.IsInstanceOfType(addressResult.Result, typeof(FormulaRangeAddress)); //var rangeResult = (FormulaRangeAddress)addressResult.Result; diff --git a/src/EPPlusTest/InCellImages/WebImagesTests.cs b/src/EPPlusTest/InCellImages/WebImagesTests.cs index de808742b7..16ec858bc6 100644 --- a/src/EPPlusTest/InCellImages/WebImagesTests.cs +++ b/src/EPPlusTest/InCellImages/WebImagesTests.cs @@ -22,7 +22,7 @@ public void LoadSimpleWorkbook1() var webPic = sheet.Cells["A1"].Picture.Get(); var uri = webPic.ImageUri; - //sheet.Cells["A2"].Picture.Set(Resources.Png2ByteArray); + //sheet.Cells["A2"].Blip.Set(Resources.Png2ByteArray); var localPic = sheet.Cells["B1"].Picture.Get(); var lpBytes = localPic.GetImageBytes(); diff --git a/src/EPPlusTest/Issues/ChartIssues.cs b/src/EPPlusTest/Issues/ChartIssues.cs index 4894625adf..8051b85384 100644 --- a/src/EPPlusTest/Issues/ChartIssues.cs +++ b/src/EPPlusTest/Issues/ChartIssues.cs @@ -117,7 +117,7 @@ public void s598() chart.Legend.TextSettings.Fill.Style = OfficeOpenXml.Drawing.eFillStyle.SolidFill; chart.Legend.TextSettings.Fill.SolidFill.Color.SetRgbColor(System.Drawing.Color.Black); - chart.Legend.TextSettings.Fill.Transparancy = 0; + chart.Legend.TextSettings.Fill.Transparency = 0; chart.Legend.TextSettings.Effect.SetPresetReflection(OfficeOpenXml.Drawing.ePresetExcelReflectionType.FullTouching); SaveAndCleanup(p); diff --git a/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs b/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs index b9ad62b69e..3c4db3c2db 100644 --- a/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs +++ b/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs @@ -1,11 +1,13 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OfficeOpenXml; +using OfficeOpenXml.Compatibility.System.Drawing; using OfficeOpenXml.ConditionalFormatting; using OfficeOpenXml.ConditionalFormatting.Contracts; using OfficeOpenXml.Style; using System.Drawing; using System.Globalization; using System.Threading; +using ColorTranslator = System.Drawing.ColorTranslator; namespace EPPlusTest.Issues { diff --git a/src/EPPlusTest/Issues/DrawingIssues.cs b/src/EPPlusTest/Issues/DrawingIssues.cs index c0c621402c..4282f09521 100644 --- a/src/EPPlusTest/Issues/DrawingIssues.cs +++ b/src/EPPlusTest/Issues/DrawingIssues.cs @@ -165,7 +165,28 @@ public void ThreeDModel() Assert.AreEqual(1, p.Workbook.Worksheets[0].Drawings.Count); SaveAndCleanup(p); } + [TestMethod] + //i2201 See #2201 + public void EnsureWhiteSpaceIsPreservedInShapes() + { + var ms = new MemoryStream(); + using (var origP = new ExcelPackage("whiteSpace.xlsx")) + { + var ws = origP.Workbook.Worksheets.Add("newWs"); + var txtBox = ws.Drawings.AddTextbox("txtbox1", " "); + origP.SaveAs(ms); + } + + string retText = ""; + using (var readP = new ExcelPackage(ms)) + { + var myShape = readP.Workbook.Worksheets[0].Drawings[0].As.Shape; + retText = myShape.Text; + } + + Assert.AreEqual(" ", retText); + } [TestMethod] public void i2278() { @@ -195,7 +216,7 @@ public void i2303() SaveAndCleanup(package); } - } + } [TestMethod] public void s1045() { diff --git a/src/EPPlusTest/Issues/FormulaCalculationIssues.cs b/src/EPPlusTest/Issues/FormulaCalculationIssues.cs index 149b54db18..ca6b0696d7 100644 --- a/src/EPPlusTest/Issues/FormulaCalculationIssues.cs +++ b/src/EPPlusTest/Issues/FormulaCalculationIssues.cs @@ -1626,7 +1626,6 @@ public void s1048() // Attach the logger before the calculation is performed. p.Workbook.FormulaParserManager.AttachLogger(logfile); - //ws.Cells["C56"].Calculate(new ExcelCalculationOption() { AllowCircularReferences = true }); p.Workbook.CalcMode = ExcelCalcMode.Manual; p.Workbook.FullCalcOnLoad = false; @@ -1680,5 +1679,4 @@ public void s1054() } } } -} - +} \ No newline at end of file diff --git a/src/EPPlusTest/Issues/LegacyTests/Issues.cs b/src/EPPlusTest/Issues/LegacyTests/Issues.cs index 90fdeb035e..d75ab7d83f 100644 --- a/src/EPPlusTest/Issues/LegacyTests/Issues.cs +++ b/src/EPPlusTest/Issues/LegacyTests/Issues.cs @@ -1250,7 +1250,7 @@ public void Issue99() using (var p = OpenTemplatePackage("Issue-99-2.xlsx")) { //var p2 = OpenPackage("Issue99-2Saved-new.xlsx", true); - //var ws = p2.Workbook.Worksheets.Add("Picture"); + //var ws = p2.Workbook.Worksheets.Add("Blip"); //ws.Drawings.AddPicture("Test1", Properties.Resources.Test1); //p.Workbook.Worksheets.Add("copy1", p.Workbook.Worksheets[0]); //p2.Workbook.Worksheets.Add("copy1", p.Workbook.Worksheets[0]); @@ -5460,7 +5460,7 @@ public void Issue1096() cells.ForEach(x => { x.Value = "test"; - //x.Style.Font.Size = 10; + //x.Style.Font.FontSize = 10; }); wss.Column(2).Style.Font.Name = "Wingdings"; @@ -5482,7 +5482,7 @@ public void Issue1096() { x.Value = "hola"; //x.Style.Font.Name = "Wingdings"; - //x.Style.Font.Size = 10; + //x.Style.Font.FontSize = 10; }); void DebugGetFontInfo() diff --git a/src/EPPlusTest/Issues/PackageIssues.cs b/src/EPPlusTest/Issues/PackageIssues.cs index 92389dc468..8bb6d73d8c 100644 --- a/src/EPPlusTest/Issues/PackageIssues.cs +++ b/src/EPPlusTest/Issues/PackageIssues.cs @@ -19,7 +19,7 @@ public static void Init(TestContext context) } [ClassCleanup] public static void Cleanup() - { + { } [TestInitialize] public void Initialize() @@ -146,6 +146,15 @@ public void s908() SaveAndCleanup(package); } } + [TestMethod] + public void s974() + { + using (ExcelPackage package = OpenTemplatePackage("s974.xlsx")) + { + var ws = package.Workbook.Worksheets[0]; + var v = ws.Cells["E2419"].Value; + } + } [TestMethod] public void i2235() diff --git a/src/EPPlusTest/Issues/PivotTableIssues.cs b/src/EPPlusTest/Issues/PivotTableIssues.cs index 5f0ec24013..be7a2f7cdc 100644 --- a/src/EPPlusTest/Issues/PivotTableIssues.cs +++ b/src/EPPlusTest/Issues/PivotTableIssues.cs @@ -581,7 +581,6 @@ public void s942() SaveAndCleanup(p); } } - [TestMethod] public void s993() { diff --git a/src/EPPlusTest/Issues/RangeTextIssues.cs b/src/EPPlusTest/Issues/RangeTextIssues.cs index 9db0536dc6..027abf620f 100644 --- a/src/EPPlusTest/Issues/RangeTextIssues.cs +++ b/src/EPPlusTest/Issues/RangeTextIssues.cs @@ -65,5 +65,26 @@ public void i1964() Assert.AreEqual("2021-12-31", cell); } } + [TestMethod] + public void i2276() + { + using (var package = OpenTemplatePackage("CurrencyTest2.xlsx")) + { + SwitchToCulture("nl-NL"); + ExcelWorkbook workbook = package.Workbook; + ExcelWorksheet worksheet = workbook.Worksheets[0]; + + Assert.AreEqual("€ 12 347", worksheet.Cells["A1"].Text); + Assert.AreEqual("[$€-2]\\ #,##0", worksheet.Cells["A1"].Style.Numberformat.Format); + Assert.AreEqual("€ 12 346,78", worksheet.Cells["D1"].Text); + Assert.AreEqual("[$€-2]\\ #,##0.00", worksheet.Cells["D1"].Style.Numberformat.Format); + + Assert.AreEqual("€ 12.347", worksheet.Cells["A2"].Text); + Assert.AreEqual("\"€\"\\ #,##0", worksheet.Cells["A2"].Style.Numberformat.Format); + Assert.AreEqual("€ 12.346,78", worksheet.Cells["D2"].Text); + Assert.AreEqual("\"€\"\\ #,##0.00", worksheet.Cells["D2"].Style.Numberformat.Format); + SwitchBackToCurrentCulture(); + } + } } } diff --git a/src/EPPlusTest/Issues/WorksheetIssues.cs b/src/EPPlusTest/Issues/WorksheetIssues.cs index c767615ccf..adf4fe6a98 100644 --- a/src/EPPlusTest/Issues/WorksheetIssues.cs +++ b/src/EPPlusTest/Issues/WorksheetIssues.cs @@ -1113,6 +1113,16 @@ public void i2240() SaveAndCleanup(package); } } + + [TestMethod] + public void s995() + { + using(var package = OpenTemplatePackage("xrIgnorableRemoved.xlsx")) + { + package.Workbook.Worksheets.Add("SecondWs"); + SaveAndCleanup(package); + } + } [TestMethod] public void testRepro() { @@ -1181,7 +1191,6 @@ public void InsertAndShift_ShouldNotThrow_WhenArrayIsFull() sheet.InsertColumn(3, 1); sheet.InsertColumn(5, 1); } - [TestMethod] public void Issue2325() { @@ -1192,6 +1201,5 @@ public void Issue2325() }); Assert.IsTrue(ex.Message.Contains("Strict Open XML")); } - } } diff --git a/src/EPPlusTest/LoadFunctions/LoadFromDataTableTests.cs b/src/EPPlusTest/LoadFunctions/LoadFromDataTableTests.cs index a2e81542a4..18441cedb6 100644 --- a/src/EPPlusTest/LoadFunctions/LoadFromDataTableTests.cs +++ b/src/EPPlusTest/LoadFunctions/LoadFromDataTableTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OfficeOpenXml; +using OfficeOpenXml.Style; using OfficeOpenXml.Table; using System; using System.Collections.Generic; @@ -67,17 +68,20 @@ public void CreateAndFillDataTable() table.Columns.Add("Id", typeof(int)); table.Columns.Add("FirstName", typeof(string)); table.Columns.Add("LastName", typeof(string)); + table.Columns.Add("Date", typeof(System.DateTime)); table.Columns["FirstName"].Caption = "First name"; table.Columns["LastName"].Caption = "Last name"; // add some data - table.Rows.Add(1, "Bob", "Behnken"); - table.Rows.Add(2, "Doug", "Hurley"); + table.Rows.Add(1, "Bob", "Behnken", DateTime.UtcNow); + table.Rows.Add(2, "Doug", "Hurley", DateTime.UtcNow); //create a workbook with a spreadsheet and load the data table using(var package = new ExcelPackage()) { var sheet = package.Workbook.Worksheets.Add("Astronauts"); sheet.Cells["A1"].LoadFromDataTable(table); + sheet.Cells["D"].Style.Numberformat.Format = "mm-dd-yy"; + package.SaveAs("C:\\epplusTest\\Testoutput\\dateDataTable.xlsx"); } } diff --git a/src/EPPlusTest/Properties/AssemblyInfo.cs b/src/EPPlusTest/Properties/AssemblyInfo.cs index cd6ac2673e..c0ce1dceda 100644 --- a/src/EPPlusTest/Properties/AssemblyInfo.cs +++ b/src/EPPlusTest/Properties/AssemblyInfo.cs @@ -53,7 +53,7 @@ Date Author Change //// Version information for an assembly consists of the following four values: //// -//// Major Version +//// MajorInterval Version //// Minor Version //// Build Number //// Revision diff --git a/src/EPPlusTest/Style/RichTextTest.cs b/src/EPPlusTest/Style/RichTextTest.cs index 48a2ab3355..c43e2e56f6 100644 --- a/src/EPPlusTest/Style/RichTextTest.cs +++ b/src/EPPlusTest/Style/RichTextTest.cs @@ -65,17 +65,17 @@ public void RichTextPropertiesReadTest() //Test Normal Text Assert.AreEqual("This is just a string of poor text… :(", ws.Cells["A1"].Text); Assert.AreEqual("This is just a string of poor text… :(", ws.Cells["A1"].RichText[0].Text); - //Test Bold + //Test FontBold Assert.AreEqual(true, ws.Cells["A2"].RichText[1].Bold); - //Test Italic + //Test FontItalic Assert.AreEqual(true, ws.Cells["A3"].RichText[1].Italic); - //Test Strike + //Test FontStrike Assert.AreEqual(true, ws.Cells["A4"].RichText[1].Strike); Assert.AreEqual(true, ws.Cells["A4"].RichText[3].Strike); //Test Vertical alignment Assert.AreEqual(ExcelVerticalAlignmentFont.Superscript, ws.Cells["A5"].RichText[1].VerticalAlign); Assert.AreEqual(ExcelVerticalAlignmentFont.Subscript, ws.Cells["A5"].RichText[3].VerticalAlign); - //Test Size + //Test FontSize Assert.AreEqual(26, ws.Cells["A6"].RichText[1].Size); //Test Font Assert.AreEqual("Arial", ws.Cells["A7"].RichText[1].FontName); @@ -368,7 +368,6 @@ public void CheckRichTextProperties() Assert.AreEqual(C4.Style.Font.Name, C4.RichText[0].FontName); Assert.AreEqual(C4.Style.Font.Size, C4.RichText[0].Size); Assert.AreEqual("Arial", C4.RichText[1].FontName); - } [TestMethod] diff --git a/src/EPPlusTest/Table/TableTests.cs b/src/EPPlusTest/Table/TableTests.cs index e575ff0614..8dfbc49f5a 100644 --- a/src/EPPlusTest/Table/TableTests.cs +++ b/src/EPPlusTest/Table/TableTests.cs @@ -35,6 +35,7 @@ Date Author Change using System.Data; using System.Drawing; using System.Globalization; +using System.Security; namespace EPPlusTest.Table { @@ -178,7 +179,6 @@ public void TableTest() ws.Cells["B1"].Value = 123; var tbl = ws.Tables.Add(ws.Cells["B1:P12"], "TestTable"); tbl.TableStyle = OfficeOpenXml.Table.TableStyles.Custom; - tbl.ShowFirstColumn = true; tbl.ShowTotal = true; tbl.ShowHeader = true; @@ -228,6 +228,10 @@ public void TableTest() tbl.ShowTotal = true; tbl.ShowFilter = false; tbl.Columns[0].TotalsRowFunction = OfficeOpenXml.Table.RowFunctions.Sum; + + var exp = tbl.CreateHtmlExporter(); + var html = exp.GetSinglePage(); + } [TestMethod] diff --git a/src/EPPlusTest/TestBase.cs b/src/EPPlusTest/TestBase.cs index 2cd27f33c3..6496ca8bc2 100644 --- a/src/EPPlusTest/TestBase.cs +++ b/src/EPPlusTest/TestBase.cs @@ -56,7 +56,7 @@ private class GeoData public string State { get; set; } public double Sales { get; set; } } - protected static FileInfo _file; + //protected static FileInfo _file; protected static string _clipartPath =""; protected static string _worksheetPath = @"c:\epplusTest\Testoutput\"; protected static string _testInputPath = AppContext.BaseDirectory + "\\workbooks\\"; @@ -135,29 +135,29 @@ protected static void AssertIfNotExists(string name) protected static ExcelPackage OpenPackage(string name, bool delete=false) { CreateWorksheetPathIfNotExists(); - _file = new FileInfo(_worksheetPath + name); - if(delete && _file.Exists) + var file = new FileInfo(_worksheetPath + name); + if(delete && file.Exists) { - _file.Delete(); + file.Delete(); } - return new ExcelPackage(_file); + return new ExcelPackage(file); } protected static async Task OpenPackageAsync(string name, bool delete = false, string password=null) { CreateWorksheetPathIfNotExists(); - var _file = new FileInfo(_worksheetPath + name); - if (delete && _file.Exists) + var file = new FileInfo(_worksheetPath + name); + if (delete && file.Exists) { - _file.Delete(); + file.Delete(); } var p = new ExcelPackage(); if (password == null) { - await p.LoadAsync(_file).ConfigureAwait(false); + await p.LoadAsync(file).ConfigureAwait(false); } else { - await p.LoadAsync(_file, password).ConfigureAwait(false); + await p.LoadAsync(file, password).ConfigureAwait(false); } return p; } diff --git a/src/EPPlusTest/WorkSheetTests.cs b/src/EPPlusTest/WorkSheetTests.cs index f9fe27debb..9f6422f2ed 100644 --- a/src/EPPlusTest/WorkSheetTests.cs +++ b/src/EPPlusTest/WorkSheetTests.cs @@ -45,6 +45,7 @@ Date Author Change using System.Runtime.InteropServices; using System.Threading.Tasks; using OfficeOpenXml.Utils.Formula; +using System.Diagnostics; namespace EPPlusTest { @@ -1117,13 +1118,13 @@ public void CopyWorksheetDefinedNamesEpplusOnly() var wb = p.Workbook; var ws = p.Workbook.Worksheets[0]; - using (var p2 = OpenPackage("CopyNamesEpplus_copied.xlsx",true)) + using (var p2 = OpenPackage("CopyNamesEpplus_copied.xlsx", true)) { var wb2 = p2.Workbook; var ws2 = wb2.Worksheets.Add("CopyWs", ws); var ws3 = wb2.Worksheets.Add("CopyWs2", ws); - Assert.AreEqual(1 ,wb2.Names.Count()); + Assert.AreEqual(1, wb2.Names.Count()); Assert.AreEqual(wb2.Names.ContainsKey("AWorkbookRange"), wb.Names.ContainsKey("AWorkbookRange")); SaveAndCleanup(p2); } @@ -1870,7 +1871,7 @@ public void SetHeaderFooterImage() Assert.AreEqual(img.Width, 426); img.Width /= 4; - Assert.AreEqual(img.Height, 49.5); + Assert.AreEqual(img.Height, 49.5); img.Height /= 4; Assert.AreEqual(img.Left, 0); Assert.AreEqual(img.Top, 0); @@ -1941,7 +1942,7 @@ public void HeaderFooterAddFormatCodes() { using var p = new ExcelPackage(); var ws = p.Workbook.Worksheets.Add("Sheet 1"); - + var t = ws.HeaderFooter.OddHeader.LeftAligned.AddText("Page: "); ws.HeaderFooter.OddHeader.LeftAligned.AddPageNumber(); ws.HeaderFooter.OddHeader.LeftAligned.AddText(" of "); @@ -2420,7 +2421,7 @@ private static void AddSortingData(ExcelWorksheet ws, int row, int col) /// Get exception from thrown from /// /// - /// Type of value to attempt getting from + /// BulletType of value to attempt getting from /// /// /// Mandatory, cell range from which to attempt getting typed value @@ -2744,7 +2745,7 @@ public void i1689() wsF.Cells["A1:A6"].Calculate(); - for(int i = 1; i<= 6; i++ ) + for (int i = 1; i <= 6; i++) { Assert.AreEqual((double)i, wsF.Cells[$"A{i}"].Value); } @@ -2811,18 +2812,169 @@ internal ExcelRangeBase GenerateRowsFromTemplate(ExcelWorksheet wks, ExcelRangeB } [TestMethod] - public void InsertRowIssue() + public void testRepro() { - using (var p = OpenTemplatePackage("s1019.xlsx")) + SwitchToCulture(""); + using (ExcelPackage p = OpenTemplatePackage("reproTimesheets - Copy.xlsx")) { - var ws = p.Workbook.Worksheets.GetByName("披露附注"); - var namedRange = ws.Names["上一行"]; + var Styles = p.Workbook.Styles; + + p.Workbook.Worksheets[0].Cells["A10"].Style.Font.Bold = true; + p.Workbook.Worksheets[0].Cells["A10"].Value = "Debugging"; + + p.Workbook.Worksheets.Add("SomeSheet"); + p.Workbook.Worksheets[1].Cells["A10"].Value = "Debugging2"; + //p.Workbook.Worksheets.Add("mt"); + //p.Workbook.Worksheets.Add("mt2"); + + Stream fs = File.Create(("C:\\epplusTest\\Testoutput\\" + "reproTimesheets.xlsx").Replace("file://", "")); + p.SaveAs(fs); + fs.Close(); + //Styles.Add("MMDDYYYY", new XLSStyle() { NumberFormat = "m/d/yyyy" }); + //Styles.Add("YYYYMMDD HHMMSS", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm:ss" }); + //Styles.Add("YYYYMMDD HHMM", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm" }); + //Styles.Add("Currency", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;;@" }); + //Styles.Add("Currency2", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;$#,##0.00;@" }); + //Styles.Add("BlankIfZero", new XLSStyle() { NumberFormat = "#.00;-#.00;;@" }); + //Styles.Add("BlankIfZeroInt", new XLSStyle() { NumberFormat = "#;-#;;@" }); + //Styles.Add("BlankIfZeroPercent", new XLSStyle() { NumberFormat = "#.00%;-#.00%;;@" }); + //Styles.Add("Header", new XLSStyle() { Font = new XLSFont() { Size = 14, Bold = true } }); + //Styles.Add("Bold", new XLSStyle() { Font = new XLSFont() { Bold = true } }); + //Styles.Add("HeaderRowLabel", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right } }); + //Styles.Add("RowLabel", new XLSStyle() { Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right }, Font = new XLSFont() { Bold = true } }); + //Styles.Add("RowLabelCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("HeaderCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("Underlined", new XLSStyle() { Font = new XLSFont() { Underline = true } }); + } + SwitchBackToCurrentCulture(); + } - var adress = namedRange.Address; + [TestMethod] + public void testHeaders() + { + SwitchToCulture("sv-SE"); + using (ExcelPackage p = OpenPackage("somePackage.xlsx",true)) + { + var Styles = p.Workbook.Styles; + + p.Workbook.Worksheets.Add("mt"); + p.Workbook.Worksheets.Add("mt2"); + + Stream fs = File.Create(("C:\\epplusTest\\Testoutput\\" + "somePackage.xlsx").Replace("file://", "")); + p.SaveAs(fs); + fs.Close(); + //Styles.Add("MMDDYYYY", new XLSStyle() { NumberFormat = "m/d/yyyy" }); + //Styles.Add("YYYYMMDD HHMMSS", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm:ss" }); + //Styles.Add("YYYYMMDD HHMM", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm" }); + //Styles.Add("Currency", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;;@" }); + //Styles.Add("Currency2", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;$#,##0.00;@" }); + //Styles.Add("BlankIfZero", new XLSStyle() { NumberFormat = "#.00;-#.00;;@" }); + //Styles.Add("BlankIfZeroInt", new XLSStyle() { NumberFormat = "#;-#;;@" }); + //Styles.Add("BlankIfZeroPercent", new XLSStyle() { NumberFormat = "#.00%;-#.00%;;@" }); + //Styles.Add("Header", new XLSStyle() { Font = new XLSFont() { Size = 14, Bold = true } }); + //Styles.Add("Bold", new XLSStyle() { Font = new XLSFont() { Bold = true } }); + //Styles.Add("HeaderRowLabel", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right } }); + //Styles.Add("RowLabel", new XLSStyle() { Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right }, Font = new XLSFont() { Bold = true } }); + //Styles.Add("RowLabelCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("HeaderCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("Underlined", new XLSStyle() { Font = new XLSFont() { Underline = true } }); + } + SwitchBackToCurrentCulture(); + } - ws.InsertRow(347, 1, 346); - SaveAndCleanup(p); + [TestMethod] + public void TestEmptyIgnorables() + { + SwitchToCulture("sv-SE"); + ExcelPackage.License.SetNonCommercialPersonal("Jan"); + + using (ExcelPackage p = OpenTemplatePackage("emptyIgnorableNamespaces.xlsx")) + { + var Styles = p.Workbook.Styles; + + List mcIgnorables = new(); + + mcIgnorables.Add("xr "); + mcIgnorables.Add(string.Empty); + mcIgnorables.Add("xr2 "); + mcIgnorables.Add(null); + mcIgnorables.Add("xr5 "); + + var result = string.Concat(mcIgnorables); + + + //var result = string.Concat(mcIgnorables, new string[] {"\r\n"}); + + //p.Workbook.Worksheets.Add("mt"); + + Stream fs = File.Create(("C:\\epplusTest\\Testoutput\\" + "emptyIgnorableNamespaces.xlsx").Replace("file://", "")); + p.SaveAs(fs); + fs.Close(); + //Styles.Add("MMDDYYYY", new XLSStyle() { NumberFormat = "m/d/yyyy" }); + //Styles.Add("YYYYMMDD HHMMSS", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm:ss" }); + //Styles.Add("YYYYMMDD HHMM", new XLSStyle() { NumberFormat = "yyyy-mm-dd hh:mm" }); + //Styles.Add("Currency", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;;@" }); + //Styles.Add("Currency2", new XLSStyle() { NumberFormat = "$#,##0.00;-$#,##0.00;$#,##0.00;@" }); + //Styles.Add("BlankIfZero", new XLSStyle() { NumberFormat = "#.00;-#.00;;@" }); + //Styles.Add("BlankIfZeroInt", new XLSStyle() { NumberFormat = "#;-#;;@" }); + //Styles.Add("BlankIfZeroPercent", new XLSStyle() { NumberFormat = "#.00%;-#.00%;;@" }); + //Styles.Add("Header", new XLSStyle() { Font = new XLSFont() { Size = 14, Bold = true } }); + //Styles.Add("Bold", new XLSStyle() { Font = new XLSFont() { Bold = true } }); + //Styles.Add("HeaderRowLabel", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right } }); + //Styles.Add("RowLabel", new XLSStyle() { Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Right }, Font = new XLSFont() { Bold = true } }); + //Styles.Add("RowLabelCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("HeaderCentered", new XLSStyle() { Font = new XLSFont() { Bold = true }, Alignment = new XLSCellAlignment() { Horizontal = ExcelHorizontalAlignment.Center } }); + //Styles.Add("Underlined", new XLSStyle() { Font = new XLSFont() { Underline = true } }); + } + + SwitchBackToCurrentCulture(); + } + + [TestMethod] + public void strangeness() + { + var aCollection = new HashSet { "a", "b" }; + var bCollection = new HashSet { "a", "b", "c" }; + var result = aCollection.Select(item => + { + if (bCollection.Contains(item)) + { + bCollection.Remove(item); + } + + return item; + }).Concat(bCollection); + + var res = result.ToString(); + } + + [TestMethod] + public void readWrite() + { + using (ExcelPackage p = OpenTemplatePackage("test998.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + ws.Cells["A1"].Value = "SomeValue"; + + Stream fs = File.Create(("C:\\epplusTest\\Testoutput\\" + "test998.xlsx").Replace("file://", "")); + p.SaveAs(fs); + fs.Close(); } } + //[TestMethod] + //public void strangenessAllMyOwn() + //{ + // const string schemaMarkupCompatibility = @"http://schemas.openxmlformats.org/markup-compatibility/2006"; + + // if (string.IsNullOrEmpty(existingIgnorables) == false) + // { + // var namespaces = existingIgnorables.Split(' '); + // //var ignorablesConcatenated = string.Concat(namespaces); + // if (namespaces.Any(x => x == "xr") == false) + // { + // WorksheetXml.DocumentElement.SetAttribute("Ignorable", ExcelPackage.schemaMarkupCompatibility, existingIgnorables + " xr"); + // } + // } + //} } } diff --git a/src/NuGet.config b/src/NuGet.config new file mode 100644 index 0000000000..cf73224c35 --- /dev/null +++ b/src/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/publickey.snk b/src/publickey.snk new file mode 100644 index 0000000000..faa3803e8c Binary files /dev/null and b/src/publickey.snk differ